@webiny/api-file-manager-s3 0.0.0-unstable.e622468070 → 0.0.0-unstable.e6f0dc8ca7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/assetDelivery/s3/SharpTransform.js +1 -1
- package/assetDelivery/s3/SharpTransform.js.map +1 -1
- package/enterprise/ApplyThreatScanning/feature.d.ts +4 -1
- package/features/DeleteFileFromBucket/DeleteFileFromBucketHandler.d.ts +4 -4
- package/features/DeleteFileFromBucket/DeleteFileFromBucketHandler.js +2 -2
- package/features/DeleteFileFromBucket/DeleteFileFromBucketHandler.js.map +1 -1
- package/features/DeleteFileFromBucket/DeleteS3FolderTask.d.ts +1 -0
- package/features/DeleteFileFromBucket/DeleteS3FolderTask.js +1 -0
- package/features/DeleteFileFromBucket/DeleteS3FolderTask.js.map +1 -1
- package/features/DeleteFileFromBucket/feature.d.ts +4 -1
- package/features/ExtractMetadata/ExtractMetadataHandler.d.ts +4 -4
- package/features/ExtractMetadata/ExtractMetadataHandler.js +2 -2
- package/features/ExtractMetadata/ExtractMetadataHandler.js.map +1 -1
- package/features/ExtractMetadata/ExtractMetadataTask.d.ts +1 -0
- package/features/ExtractMetadata/ExtractMetadataTask.js +1 -0
- package/features/ExtractMetadata/ExtractMetadataTask.js.map +1 -1
- package/features/ExtractMetadata/feature.d.ts +4 -1
- package/features/FlushCache/FlushCacheOnFileDeleteHandler.d.ts +4 -4
- package/features/FlushCache/FlushCacheOnFileDeleteHandler.js +2 -2
- package/features/FlushCache/FlushCacheOnFileDeleteHandler.js.map +1 -1
- package/features/FlushCache/FlushCacheOnFileUpdateHandler.d.ts +4 -4
- package/features/FlushCache/FlushCacheOnFileUpdateHandler.js +2 -2
- package/features/FlushCache/FlushCacheOnFileUpdateHandler.js.map +1 -1
- package/features/FlushCache/InvalidateCacheTask.d.ts +1 -0
- package/features/FlushCache/InvalidateCacheTask.js +1 -0
- package/features/FlushCache/InvalidateCacheTask.js.map +1 -1
- package/features/FlushCache/feature.d.ts +4 -1
- package/features/GetFileContents/GetFileContentsUseCase.d.ts +13 -0
- package/features/GetFileContents/GetFileContentsUseCase.js +41 -0
- package/features/GetFileContents/GetFileContentsUseCase.js.map +1 -0
- package/features/GetFileContents/feature.d.ts +4 -0
- package/features/GetFileContents/feature.js +10 -0
- package/features/GetFileContents/feature.js.map +1 -0
- package/features/WriteFileMetadata/MetadataWriter.d.ts +1 -1
- package/features/WriteFileMetadata/MetadataWriter.js.map +1 -1
- package/features/WriteFileMetadata/WriteMetadataAfterBatchCreateHandler.d.ts +5 -5
- package/features/WriteFileMetadata/WriteMetadataAfterBatchCreateHandler.js +3 -3
- package/features/WriteFileMetadata/WriteMetadataAfterBatchCreateHandler.js.map +1 -1
- package/features/WriteFileMetadata/WriteMetadataAfterCreateHandler.d.ts +4 -4
- package/features/WriteFileMetadata/WriteMetadataAfterCreateHandler.js +2 -2
- package/features/WriteFileMetadata/WriteMetadataAfterCreateHandler.js.map +1 -1
- package/features/WriteFileMetadata/feature.d.ts +4 -1
- package/graphql/checkPermissions.d.ts +1 -1
- package/graphql/checkPermissions.js.map +1 -1
- package/graphql/schema.js +1 -1
- package/graphql/schema.js.map +1 -1
- package/index.js +2 -0
- package/index.js.map +1 -1
- package/package.json +26 -22
- package/types.d.ts +1 -0
- package/types.js +1 -1
- package/types.js.map +1 -1
- package/utils/FileKey.test.js +1 -1
- package/utils/FileKey.test.js.map +1 -1
- package/utils/FileNormalizer.js +15 -1
- package/utils/FileNormalizer.js.map +1 -1
- package/utils/mimeTypes.js +0 -2
- package/utils/mimeTypes.js.map +1 -1
|
@@ -14,7 +14,7 @@ export class SharpTransform {
|
|
|
14
14
|
}
|
|
15
15
|
|
|
16
16
|
// `original` is part of the request, but it won't even get to this point in the execution.
|
|
17
|
-
//
|
|
17
|
+
// oxlint-disable-next-line typescript/no-unused-vars
|
|
18
18
|
const {
|
|
19
19
|
original,
|
|
20
20
|
...options
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["sharp","WidthCollection","utils","CallableContentsReader","AssetKeyGenerator","SharpTransform","constructor","params","transform","assetRequest","asset","SUPPORTED_TRANSFORMABLE_IMAGES","includes","getExtension","console","log","getContentType","original","options","getOptions","transformedAsset","clone","Object","keys","length","transformAsset","optimizeAsset","width","s3","bucket","assetKey","transformedAssetKey","getTransformedImageKey","Body","getObject","Bucket","Key","Error","buffer","Buffer","from","transformToByteArray","newAsset","withProps","size","setContentsReader","key","getSize","optimizedImage","widths","imageResizeWidths","getClosestOrMax","getContents","transformedBuffer","animated","isAssetAnimated","withMetadata","resize","withoutEnlargement","toBuffer","putObject","ContentType","id","getId","getKey","type","optimizedAssetKey","getOptimizedImageKey","optimizationMap","optimizePng","optimizeJpeg","optimization","optimizedBuffer","fit","png","compressionLevel","adaptiveFiltering","force","toFormat","quality"],"sources":["SharpTransform.ts"],"sourcesContent":["import sharp from \"sharp\";\nimport type { S3 } from \"@webiny/aws-sdk/client-s3/index.js\";\nimport type {\n Asset,\n AssetRequest,\n AssetRequestOptions,\n AssetTransformationStrategy\n} from \"@webiny/api-file-manager\";\nimport { WidthCollection } from \"./transformation/WidthCollection.js\";\nimport * as utils from \"./transformation/utils.js\";\nimport { CallableContentsReader } from \"./transformation/CallableContentsReader.js\";\nimport { AssetKeyGenerator } from \"./transformation/AssetKeyGenerator.js\";\n\ninterface SharpTransformationParams {\n s3: S3;\n bucket: string;\n imageResizeWidths: number[];\n}\n\nexport class SharpTransform implements AssetTransformationStrategy {\n private readonly params: SharpTransformationParams;\n\n constructor(params: SharpTransformationParams) {\n this.params = params;\n }\n\n async transform(assetRequest: AssetRequest, asset: Asset): Promise<Asset> {\n if (!utils.SUPPORTED_TRANSFORMABLE_IMAGES.includes(asset.getExtension())) {\n console.log(\n `Transformations/optimizations of ${asset.getContentType()} assets are not supported. Skipping.`\n );\n return asset;\n }\n\n // `original` is part of the request, but it won't even get to this point in the execution.\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n const { original, ...options } = assetRequest.getOptions();\n\n const transformedAsset = asset.clone();\n\n if (Object.keys(options).length > 0) {\n // Transformations were requested.\n return this.transformAsset(transformedAsset, options);\n }\n\n // Return an optimized asset.\n return this.optimizeAsset(transformedAsset);\n }\n\n private async transformAsset(asset: Asset, options: Omit<AssetRequestOptions, \"original\">) {\n if (options.width) {\n const { s3, bucket } = this.params;\n\n const assetKey = new AssetKeyGenerator(asset);\n const transformedAssetKey = assetKey.getTransformedImageKey(options);\n\n try {\n const { Body } = await s3.getObject({\n Bucket: bucket,\n Key: transformedAssetKey\n });\n\n if (!Body) {\n throw new Error(`Missing image body!`);\n }\n\n const buffer = Buffer.from(await Body.transformToByteArray());\n\n const newAsset = asset.withProps({ size: buffer.length });\n newAsset.setContentsReader(new CallableContentsReader(() => buffer));\n\n console.log(`Return a previously transformed asset`, {\n key: transformedAssetKey,\n size: newAsset.getSize()\n });\n\n return newAsset;\n } catch {\n const optimizedImage = await this.optimizeAsset(asset);\n\n const widths = new WidthCollection(this.params.imageResizeWidths);\n const width = widths.getClosestOrMax(options.width);\n\n /**\n * `width` is the only transformation we currently support.\n */\n console.log(`Resize the asset (width: ${width})`);\n const buffer = await optimizedImage.getContents();\n const transformedBuffer = await sharp(buffer, {\n animated: this.isAssetAnimated(asset)\n })\n .withMetadata()\n .resize({ width, withoutEnlargement: true })\n .toBuffer();\n\n /**\n * Transformations are applied to the optimized image.\n */\n const newAsset = asset.withProps({ size: transformedBuffer.length });\n newAsset.setContentsReader(new CallableContentsReader(() => transformedBuffer));\n\n await s3.putObject({\n Bucket: bucket,\n Key: transformedAssetKey,\n ContentType: newAsset.getContentType(),\n Body: await newAsset.getContents()\n });\n\n console.log(`Return the resized asset`, {\n key: transformedAssetKey,\n size: newAsset.getSize()\n });\n\n return newAsset;\n }\n }\n\n return asset;\n }\n\n private async optimizeAsset(asset: Asset) {\n const { s3, bucket } = this.params;\n\n console.log(\"Optimize asset\", {\n id: asset.getId(),\n key: asset.getKey(),\n size: asset.getSize(),\n type: asset.getContentType()\n });\n\n const assetKey = new AssetKeyGenerator(asset);\n const optimizedAssetKey = assetKey.getOptimizedImageKey();\n\n try {\n const { Body } = await s3.getObject({\n Bucket: bucket,\n Key: optimizedAssetKey\n });\n\n if (!Body) {\n throw new Error(`Missing image body!`);\n }\n\n console.log(\"Return a previously optimized asset\", optimizedAssetKey);\n\n const buffer = Buffer.from(await Body.transformToByteArray());\n\n const newAsset = asset.withProps({ size: buffer.length });\n newAsset.setContentsReader(new CallableContentsReader(() => buffer));\n\n return newAsset;\n } catch {\n console.log(\"Create an optimized version of the original asset\", asset.getKey());\n // If not found, create an optimized version of the original asset.\n const buffer = await asset.getContents();\n\n const optimizationMap: Record<string, ((buffer: Buffer) => sharp.Sharp) | undefined> = {\n \"image/png\": (buffer: Buffer) => this.optimizePng(buffer),\n \"image/jpeg\": (buffer: Buffer) => this.optimizeJpeg(buffer),\n \"image/jpg\": (buffer: Buffer) => this.optimizeJpeg(buffer)\n };\n\n const optimization = optimizationMap[asset.getContentType()];\n\n if (!optimization) {\n console.log(`No optimizations defined for ${asset.getContentType()}`);\n return asset;\n }\n\n const optimizedBuffer = await optimization(buffer).toBuffer();\n\n console.log(\"Optimized asset size\", optimizedBuffer.length);\n\n const newAsset = asset.withProps({ size: optimizedBuffer.length });\n newAsset.setContentsReader(new CallableContentsReader(() => optimizedBuffer));\n\n await s3.putObject({\n Bucket: bucket,\n Key: optimizedAssetKey,\n ContentType: newAsset.getContentType(),\n Body: await newAsset.getContents()\n });\n\n return newAsset;\n }\n }\n\n private isAssetAnimated(asset: Asset) {\n return [\"gif\", \"webp\"].includes(asset.getExtension());\n }\n\n private optimizePng(buffer: Buffer) {\n return sharp(buffer)\n .resize({ width: 2560, withoutEnlargement: true, fit: \"inside\" })\n .png({ compressionLevel: 9, adaptiveFiltering: true, force: true })\n .withMetadata();\n }\n\n private optimizeJpeg(buffer: Buffer) {\n return sharp(buffer)\n .resize({ width: 2560, withoutEnlargement: true, fit: \"inside\" })\n .withMetadata()\n .toFormat(\"jpeg\", { quality: 90 });\n }\n}\n"],"mappings":"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","ignoreList":[]}
|
|
1
|
+
{"version":3,"names":["sharp","WidthCollection","utils","CallableContentsReader","AssetKeyGenerator","SharpTransform","constructor","params","transform","assetRequest","asset","SUPPORTED_TRANSFORMABLE_IMAGES","includes","getExtension","console","log","getContentType","original","options","getOptions","transformedAsset","clone","Object","keys","length","transformAsset","optimizeAsset","width","s3","bucket","assetKey","transformedAssetKey","getTransformedImageKey","Body","getObject","Bucket","Key","Error","buffer","Buffer","from","transformToByteArray","newAsset","withProps","size","setContentsReader","key","getSize","optimizedImage","widths","imageResizeWidths","getClosestOrMax","getContents","transformedBuffer","animated","isAssetAnimated","withMetadata","resize","withoutEnlargement","toBuffer","putObject","ContentType","id","getId","getKey","type","optimizedAssetKey","getOptimizedImageKey","optimizationMap","optimizePng","optimizeJpeg","optimization","optimizedBuffer","fit","png","compressionLevel","adaptiveFiltering","force","toFormat","quality"],"sources":["SharpTransform.ts"],"sourcesContent":["import sharp from \"sharp\";\nimport type { S3 } from \"@webiny/aws-sdk/client-s3/index.js\";\nimport type {\n Asset,\n AssetRequest,\n AssetRequestOptions,\n AssetTransformationStrategy\n} from \"@webiny/api-file-manager\";\nimport { WidthCollection } from \"./transformation/WidthCollection.js\";\nimport * as utils from \"./transformation/utils.js\";\nimport { CallableContentsReader } from \"./transformation/CallableContentsReader.js\";\nimport { AssetKeyGenerator } from \"./transformation/AssetKeyGenerator.js\";\n\ninterface SharpTransformationParams {\n s3: S3;\n bucket: string;\n imageResizeWidths: number[];\n}\n\nexport class SharpTransform implements AssetTransformationStrategy {\n private readonly params: SharpTransformationParams;\n\n constructor(params: SharpTransformationParams) {\n this.params = params;\n }\n\n async transform(assetRequest: AssetRequest, asset: Asset): Promise<Asset> {\n if (!utils.SUPPORTED_TRANSFORMABLE_IMAGES.includes(asset.getExtension())) {\n console.log(\n `Transformations/optimizations of ${asset.getContentType()} assets are not supported. Skipping.`\n );\n return asset;\n }\n\n // `original` is part of the request, but it won't even get to this point in the execution.\n // oxlint-disable-next-line typescript/no-unused-vars\n const { original, ...options } = assetRequest.getOptions();\n\n const transformedAsset = asset.clone();\n\n if (Object.keys(options).length > 0) {\n // Transformations were requested.\n return this.transformAsset(transformedAsset, options);\n }\n\n // Return an optimized asset.\n return this.optimizeAsset(transformedAsset);\n }\n\n private async transformAsset(asset: Asset, options: Omit<AssetRequestOptions, \"original\">) {\n if (options.width) {\n const { s3, bucket } = this.params;\n\n const assetKey = new AssetKeyGenerator(asset);\n const transformedAssetKey = assetKey.getTransformedImageKey(options);\n\n try {\n const { Body } = await s3.getObject({\n Bucket: bucket,\n Key: transformedAssetKey\n });\n\n if (!Body) {\n throw new Error(`Missing image body!`);\n }\n\n const buffer = Buffer.from(await Body.transformToByteArray());\n\n const newAsset = asset.withProps({ size: buffer.length });\n newAsset.setContentsReader(new CallableContentsReader(() => buffer));\n\n console.log(`Return a previously transformed asset`, {\n key: transformedAssetKey,\n size: newAsset.getSize()\n });\n\n return newAsset;\n } catch {\n const optimizedImage = await this.optimizeAsset(asset);\n\n const widths = new WidthCollection(this.params.imageResizeWidths);\n const width = widths.getClosestOrMax(options.width);\n\n /**\n * `width` is the only transformation we currently support.\n */\n console.log(`Resize the asset (width: ${width})`);\n const buffer = await optimizedImage.getContents();\n const transformedBuffer = await sharp(buffer, {\n animated: this.isAssetAnimated(asset)\n })\n .withMetadata()\n .resize({ width, withoutEnlargement: true })\n .toBuffer();\n\n /**\n * Transformations are applied to the optimized image.\n */\n const newAsset = asset.withProps({ size: transformedBuffer.length });\n newAsset.setContentsReader(new CallableContentsReader(() => transformedBuffer));\n\n await s3.putObject({\n Bucket: bucket,\n Key: transformedAssetKey,\n ContentType: newAsset.getContentType(),\n Body: await newAsset.getContents()\n });\n\n console.log(`Return the resized asset`, {\n key: transformedAssetKey,\n size: newAsset.getSize()\n });\n\n return newAsset;\n }\n }\n\n return asset;\n }\n\n private async optimizeAsset(asset: Asset) {\n const { s3, bucket } = this.params;\n\n console.log(\"Optimize asset\", {\n id: asset.getId(),\n key: asset.getKey(),\n size: asset.getSize(),\n type: asset.getContentType()\n });\n\n const assetKey = new AssetKeyGenerator(asset);\n const optimizedAssetKey = assetKey.getOptimizedImageKey();\n\n try {\n const { Body } = await s3.getObject({\n Bucket: bucket,\n Key: optimizedAssetKey\n });\n\n if (!Body) {\n throw new Error(`Missing image body!`);\n }\n\n console.log(\"Return a previously optimized asset\", optimizedAssetKey);\n\n const buffer = Buffer.from(await Body.transformToByteArray());\n\n const newAsset = asset.withProps({ size: buffer.length });\n newAsset.setContentsReader(new CallableContentsReader(() => buffer));\n\n return newAsset;\n } catch {\n console.log(\"Create an optimized version of the original asset\", asset.getKey());\n // If not found, create an optimized version of the original asset.\n const buffer = await asset.getContents();\n\n const optimizationMap: Record<string, ((buffer: Buffer) => sharp.Sharp) | undefined> = {\n \"image/png\": (buffer: Buffer) => this.optimizePng(buffer),\n \"image/jpeg\": (buffer: Buffer) => this.optimizeJpeg(buffer),\n \"image/jpg\": (buffer: Buffer) => this.optimizeJpeg(buffer)\n };\n\n const optimization = optimizationMap[asset.getContentType()];\n\n if (!optimization) {\n console.log(`No optimizations defined for ${asset.getContentType()}`);\n return asset;\n }\n\n const optimizedBuffer = await optimization(buffer).toBuffer();\n\n console.log(\"Optimized asset size\", optimizedBuffer.length);\n\n const newAsset = asset.withProps({ size: optimizedBuffer.length });\n newAsset.setContentsReader(new CallableContentsReader(() => optimizedBuffer));\n\n await s3.putObject({\n Bucket: bucket,\n Key: optimizedAssetKey,\n ContentType: newAsset.getContentType(),\n Body: await newAsset.getContents()\n });\n\n return newAsset;\n }\n }\n\n private isAssetAnimated(asset: Asset) {\n return [\"gif\", \"webp\"].includes(asset.getExtension());\n }\n\n private optimizePng(buffer: Buffer) {\n return sharp(buffer)\n .resize({ width: 2560, withoutEnlargement: true, fit: \"inside\" })\n .png({ compressionLevel: 9, adaptiveFiltering: true, force: true })\n .withMetadata();\n }\n\n private optimizeJpeg(buffer: Buffer) {\n return sharp(buffer)\n .resize({ width: 2560, withoutEnlargement: true, fit: \"inside\" })\n .withMetadata()\n .toFormat(\"jpeg\", { quality: 90 });\n }\n}\n"],"mappings":"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","ignoreList":[]}
|
|
@@ -1,15 +1,15 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { FileAfterDeleteEventHandler } from "@webiny/api-file-manager/features/file/DeleteFile/events.js";
|
|
2
2
|
import { TaskService } from "@webiny/api-core/features/task/TaskService/index.js";
|
|
3
3
|
import { GlobalKeyValueStore } from "@webiny/api-core/features/keyValueStore/index.js";
|
|
4
4
|
import { TenantContext } from "@webiny/api-core/features/tenancy/TenantContext/index.js";
|
|
5
|
-
declare class DeleteFileFromBucketHandlerImpl implements
|
|
5
|
+
declare class DeleteFileFromBucketHandlerImpl implements FileAfterDeleteEventHandler.Interface {
|
|
6
6
|
private tenantContext;
|
|
7
7
|
private taskService;
|
|
8
8
|
private keyValueStore;
|
|
9
9
|
constructor(tenantContext: TenantContext.Interface, taskService: TaskService.Interface, keyValueStore: GlobalKeyValueStore.Interface);
|
|
10
|
-
handle(event:
|
|
10
|
+
handle(event: FileAfterDeleteEventHandler.Event): Promise<void>;
|
|
11
11
|
}
|
|
12
12
|
export declare const DeleteFileFromBucketHandler: typeof DeleteFileFromBucketHandlerImpl & {
|
|
13
|
-
__abstraction: import("@webiny/di").Abstraction<import("@webiny/api-core/features/
|
|
13
|
+
__abstraction: import("@webiny/di").Abstraction<import("@webiny/api-core/features/eventPublisher").IEventHandler<import("@webiny/api-file-manager/features/file/DeleteFile/events.js").FileAfterDeleteEvent>>;
|
|
14
14
|
};
|
|
15
15
|
export {};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { FileAfterDeleteEventHandler } from "@webiny/api-file-manager/features/file/DeleteFile/events.js";
|
|
2
2
|
import { TaskService } from "@webiny/api-core/features/task/TaskService/index.js";
|
|
3
3
|
import { GlobalKeyValueStore } from "@webiny/api-core/features/keyValueStore/index.js";
|
|
4
4
|
import { TenantContext } from "@webiny/api-core/features/tenancy/TenantContext/index.js";
|
|
@@ -28,7 +28,7 @@ class DeleteFileFromBucketHandlerImpl {
|
|
|
28
28
|
await this.keyValueStore.delete(`FileManager/File/${file.id}/Metadata`);
|
|
29
29
|
}
|
|
30
30
|
}
|
|
31
|
-
export const DeleteFileFromBucketHandler =
|
|
31
|
+
export const DeleteFileFromBucketHandler = FileAfterDeleteEventHandler.createImplementation({
|
|
32
32
|
implementation: DeleteFileFromBucketHandlerImpl,
|
|
33
33
|
dependencies: [TenantContext, TaskService, GlobalKeyValueStore]
|
|
34
34
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["
|
|
1
|
+
{"version":3,"names":["FileAfterDeleteEventHandler","TaskService","GlobalKeyValueStore","TenantContext","DeleteFileFromBucketHandlerImpl","constructor","tenantContext","taskService","keyValueStore","handle","event","file","payload","tenant","getTenant","trigger","definition","input","caller","bucket","String","process","env","S3_BUCKET","folderKey","id","delete","DeleteFileFromBucketHandler","createImplementation","implementation","dependencies"],"sources":["DeleteFileFromBucketHandler.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 { GlobalKeyValueStore } from \"@webiny/api-core/features/keyValueStore/index.js\";\nimport type { DeleteS3FolderInput } from \"~/features/DeleteFileFromBucket/DeleteS3FolderTask.js\";\nimport { TenantContext } from \"@webiny/api-core/features/tenancy/TenantContext/index.js\";\n\nclass DeleteFileFromBucketHandlerImpl implements FileAfterDeleteEventHandler.Interface {\n constructor(\n private tenantContext: TenantContext.Interface,\n private taskService: TaskService.Interface,\n private keyValueStore: GlobalKeyValueStore.Interface\n ) {}\n\n async handle(event: FileAfterDeleteEventHandler.Event): Promise<void> {\n const { file } = event.payload;\n const tenant = this.tenantContext.getTenant();\n\n // Delete S3 folder recursively\n await this.taskService.trigger<DeleteS3FolderInput>({\n definition: \"fileManagerFolderDelete\",\n input: {\n caller: \"fm-after-delete\",\n bucket: String(process.env.S3_BUCKET),\n folderKey: `tenants/${tenant.id}/files/${file.id}`\n }\n });\n\n // Delete file metadata\n await this.keyValueStore.delete(`FileManager/File/${file.id}/Metadata`);\n }\n}\n\nexport const DeleteFileFromBucketHandler = FileAfterDeleteEventHandler.createImplementation({\n implementation: DeleteFileFromBucketHandlerImpl,\n dependencies: [TenantContext, TaskService, GlobalKeyValueStore]\n});\n"],"mappings":"AAAA,SAASA,2BAA2B,QAAQ,6DAA6D;AACzG,SAASC,WAAW,QAAQ,qDAAqD;AACjF,SAASC,mBAAmB,QAAQ,kDAAkD;AAEtF,SAASC,aAAa,QAAQ,0DAA0D;AAExF,MAAMC,+BAA+B,CAAkD;EACnFC,WAAWA,CACCC,aAAsC,EACtCC,WAAkC,EAClCC,aAA4C,EACtD;IAAA,KAHUF,aAAsC,GAAtCA,aAAsC;IAAA,KACtCC,WAAkC,GAAlCA,WAAkC;IAAA,KAClCC,aAA4C,GAA5CA,aAA4C;EACrD;EAEH,MAAMC,MAAMA,CAACC,KAAwC,EAAiB;IAClE,MAAM;MAAEC;IAAK,CAAC,GAAGD,KAAK,CAACE,OAAO;IAC9B,MAAMC,MAAM,GAAG,IAAI,CAACP,aAAa,CAACQ,SAAS,CAAC,CAAC;;IAE7C;IACA,MAAM,IAAI,CAACP,WAAW,CAACQ,OAAO,CAAsB;MAChDC,UAAU,EAAE,yBAAyB;MACrCC,KAAK,EAAE;QACHC,MAAM,EAAE,iBAAiB;QACzBC,MAAM,EAAEC,MAAM,CAACC,OAAO,CAACC,GAAG,CAACC,SAAS,CAAC;QACrCC,SAAS,EAAE,WAAWX,MAAM,CAACY,EAAE,UAAUd,IAAI,CAACc,EAAE;MACpD;IACJ,CAAC,CAAC;;IAEF;IACA,MAAM,IAAI,CAACjB,aAAa,CAACkB,MAAM,CAAC,oBAAoBf,IAAI,CAACc,EAAE,WAAW,CAAC;EAC3E;AACJ;AAEA,OAAO,MAAME,2BAA2B,GAAG3B,2BAA2B,CAAC4B,oBAAoB,CAAC;EACxFC,cAAc,EAAEzB,+BAA+B;EAC/C0B,YAAY,EAAE,CAAC3B,aAAa,EAAEF,WAAW,EAAEC,mBAAmB;AAClE,CAAC,CAAC","ignoreList":[]}
|
|
@@ -23,6 +23,7 @@ declare class DeleteS3FolderTask implements TaskDefinition.Interface<DeleteS3Fol
|
|
|
23
23
|
description: string;
|
|
24
24
|
maxIterations: number;
|
|
25
25
|
isPrivate: boolean;
|
|
26
|
+
readonly selfCleanup: ("onSuccess" | "onAbort")[];
|
|
26
27
|
run({ input, controller }: TaskDefinition.RunParams<DeleteS3FolderInput>): Promise<TaskDefinition.Result<DeleteS3FolderInput>>;
|
|
27
28
|
}
|
|
28
29
|
export declare const DeleteS3FolderTaskDefinition: typeof DeleteS3FolderTask & {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["S3","TaskDefinition","DeleteS3FolderTask","id","title","description","maxIterations","isPrivate","run","input","controller","runtime","isAborted","response","aborted","bucket","error","message","s3","filesList","listObjectsV2","Bucket","Prefix","folderKey","ContinuationToken","continuationToken","Contents","length","objectsToDelete","filter","file","Key","map","deleteObjects","Delete","Objects","IsTruncated","NextContinuationToken","continue","done","DeleteS3FolderTaskDefinition","createImplementation","implementation","dependencies"],"sources":["DeleteS3FolderTask.ts"],"sourcesContent":["import { S3 } from \"@webiny/aws-sdk/client-s3/index.js\";\nimport { TaskDefinition } from \"@webiny/api-core/features/task/TaskDefinition/index.js\";\n\nexport interface DeleteS3FolderInput {\n /**\n * Caller of the task (e.g., `fm-after-delete`).\n */\n caller: string;\n /**\n * Cache paths to invalidate.\n */\n bucket: string;\n /**\n * FM file directory key to delete.\n */\n folderKey: string;\n /**\n * Continuation token for pagination.\n */\n continuationToken?: string;\n}\n\nclass DeleteS3FolderTask implements TaskDefinition.Interface<DeleteS3FolderInput> {\n id = \"fileManagerFolderDelete\";\n title = \"Delete folder and all of its contents from the bucket.\";\n description = \"A task to delete all files from a given folder.\";\n maxIterations = 5;\n isPrivate = true;\n\n public async run({\n input,\n controller\n }: TaskDefinition.RunParams<DeleteS3FolderInput>): Promise<\n TaskDefinition.Result<DeleteS3FolderInput>\n > {\n if (controller.runtime.isAborted()) {\n return controller.response.aborted();\n }\n\n if (!input.bucket) {\n return controller.response.error({ message: `Bucket is not defined.` });\n }\n\n const s3 = new S3();\n\n // List objects in the folder with pagination support.\n const filesList = await s3.listObjectsV2({\n Bucket: input.bucket,\n Prefix: `${input.folderKey}/`,\n ContinuationToken: input.continuationToken\n });\n\n // Delete all files in the folder using batch delete.\n if (filesList.Contents && filesList.Contents.length > 0) {\n const objectsToDelete = filesList.Contents.filter(file => file.Key).map(file => ({\n Key: file.Key!\n }));\n\n if (objectsToDelete.length > 0) {\n await s3.deleteObjects({\n Bucket: input.bucket,\n Delete: {\n Objects: objectsToDelete\n }\n });\n }\n }\n\n // If there are more objects to delete, continue in the next iteration.\n if (filesList.IsTruncated && filesList.NextContinuationToken) {\n return controller.response.continue({\n ...input,\n continuationToken: filesList.NextContinuationToken\n });\n }\n\n return controller.response.done();\n }\n}\n\nexport const DeleteS3FolderTaskDefinition = TaskDefinition.createImplementation({\n implementation: DeleteS3FolderTask,\n dependencies: []\n});\n"],"mappings":"AAAA,SAASA,EAAE,QAAQ,oCAAoC;AACvD,SAASC,cAAc,QAAQ,wDAAwD;AAqBvF,MAAMC,kBAAkB,CAA0D;EAC9EC,EAAE,GAAG,yBAAyB;EAC9BC,KAAK,GAAG,wDAAwD;EAChEC,WAAW,GAAG,iDAAiD;EAC/DC,aAAa,GAAG,CAAC;EACjBC,SAAS,GAAG,IAAI;
|
|
1
|
+
{"version":3,"names":["S3","TaskDefinition","DeleteS3FolderTask","id","title","description","maxIterations","isPrivate","selfCleanup","run","input","controller","runtime","isAborted","response","aborted","bucket","error","message","s3","filesList","listObjectsV2","Bucket","Prefix","folderKey","ContinuationToken","continuationToken","Contents","length","objectsToDelete","filter","file","Key","map","deleteObjects","Delete","Objects","IsTruncated","NextContinuationToken","continue","done","DeleteS3FolderTaskDefinition","createImplementation","implementation","dependencies"],"sources":["DeleteS3FolderTask.ts"],"sourcesContent":["import { S3 } from \"@webiny/aws-sdk/client-s3/index.js\";\nimport { TaskDefinition } from \"@webiny/api-core/features/task/TaskDefinition/index.js\";\n\nexport interface DeleteS3FolderInput {\n /**\n * Caller of the task (e.g., `fm-after-delete`).\n */\n caller: string;\n /**\n * Cache paths to invalidate.\n */\n bucket: string;\n /**\n * FM file directory key to delete.\n */\n folderKey: string;\n /**\n * Continuation token for pagination.\n */\n continuationToken?: string;\n}\n\nclass DeleteS3FolderTask implements TaskDefinition.Interface<DeleteS3FolderInput> {\n id = \"fileManagerFolderDelete\";\n title = \"Delete folder and all of its contents from the bucket.\";\n description = \"A task to delete all files from a given folder.\";\n maxIterations = 5;\n isPrivate = true;\n\n public readonly selfCleanup = [\"onSuccess\" as const, \"onAbort\" as const];\n\n public async run({\n input,\n controller\n }: TaskDefinition.RunParams<DeleteS3FolderInput>): Promise<\n TaskDefinition.Result<DeleteS3FolderInput>\n > {\n if (controller.runtime.isAborted()) {\n return controller.response.aborted();\n }\n\n if (!input.bucket) {\n return controller.response.error({ message: `Bucket is not defined.` });\n }\n\n const s3 = new S3();\n\n // List objects in the folder with pagination support.\n const filesList = await s3.listObjectsV2({\n Bucket: input.bucket,\n Prefix: `${input.folderKey}/`,\n ContinuationToken: input.continuationToken\n });\n\n // Delete all files in the folder using batch delete.\n if (filesList.Contents && filesList.Contents.length > 0) {\n const objectsToDelete = filesList.Contents.filter(file => file.Key).map(file => ({\n Key: file.Key!\n }));\n\n if (objectsToDelete.length > 0) {\n await s3.deleteObjects({\n Bucket: input.bucket,\n Delete: {\n Objects: objectsToDelete\n }\n });\n }\n }\n\n // If there are more objects to delete, continue in the next iteration.\n if (filesList.IsTruncated && filesList.NextContinuationToken) {\n return controller.response.continue({\n ...input,\n continuationToken: filesList.NextContinuationToken\n });\n }\n\n return controller.response.done();\n }\n}\n\nexport const DeleteS3FolderTaskDefinition = TaskDefinition.createImplementation({\n implementation: DeleteS3FolderTask,\n dependencies: []\n});\n"],"mappings":"AAAA,SAASA,EAAE,QAAQ,oCAAoC;AACvD,SAASC,cAAc,QAAQ,wDAAwD;AAqBvF,MAAMC,kBAAkB,CAA0D;EAC9EC,EAAE,GAAG,yBAAyB;EAC9BC,KAAK,GAAG,wDAAwD;EAChEC,WAAW,GAAG,iDAAiD;EAC/DC,aAAa,GAAG,CAAC;EACjBC,SAAS,GAAG,IAAI;EAEAC,WAAW,GAAG,CAAC,WAAW,EAAW,SAAS,CAAU;EAExE,MAAaC,GAAGA,CAAC;IACbC,KAAK;IACLC;EAC2C,CAAC,EAE9C;IACE,IAAIA,UAAU,CAACC,OAAO,CAACC,SAAS,CAAC,CAAC,EAAE;MAChC,OAAOF,UAAU,CAACG,QAAQ,CAACC,OAAO,CAAC,CAAC;IACxC;IAEA,IAAI,CAACL,KAAK,CAACM,MAAM,EAAE;MACf,OAAOL,UAAU,CAACG,QAAQ,CAACG,KAAK,CAAC;QAAEC,OAAO,EAAE;MAAyB,CAAC,CAAC;IAC3E;IAEA,MAAMC,EAAE,GAAG,IAAInB,EAAE,CAAC,CAAC;;IAEnB;IACA,MAAMoB,SAAS,GAAG,MAAMD,EAAE,CAACE,aAAa,CAAC;MACrCC,MAAM,EAAEZ,KAAK,CAACM,MAAM;MACpBO,MAAM,EAAE,GAAGb,KAAK,CAACc,SAAS,GAAG;MAC7BC,iBAAiB,EAAEf,KAAK,CAACgB;IAC7B,CAAC,CAAC;;IAEF;IACA,IAAIN,SAAS,CAACO,QAAQ,IAAIP,SAAS,CAACO,QAAQ,CAACC,MAAM,GAAG,CAAC,EAAE;MACrD,MAAMC,eAAe,GAAGT,SAAS,CAACO,QAAQ,CAACG,MAAM,CAACC,IAAI,IAAIA,IAAI,CAACC,GAAG,CAAC,CAACC,GAAG,CAACF,IAAI,KAAK;QAC7EC,GAAG,EAAED,IAAI,CAACC;MACd,CAAC,CAAC,CAAC;MAEH,IAAIH,eAAe,CAACD,MAAM,GAAG,CAAC,EAAE;QAC5B,MAAMT,EAAE,CAACe,aAAa,CAAC;UACnBZ,MAAM,EAAEZ,KAAK,CAACM,MAAM;UACpBmB,MAAM,EAAE;YACJC,OAAO,EAAEP;UACb;QACJ,CAAC,CAAC;MACN;IACJ;;IAEA;IACA,IAAIT,SAAS,CAACiB,WAAW,IAAIjB,SAAS,CAACkB,qBAAqB,EAAE;MAC1D,OAAO3B,UAAU,CAACG,QAAQ,CAACyB,QAAQ,CAAC;QAChC,GAAG7B,KAAK;QACRgB,iBAAiB,EAAEN,SAAS,CAACkB;MACjC,CAAC,CAAC;IACN;IAEA,OAAO3B,UAAU,CAACG,QAAQ,CAAC0B,IAAI,CAAC,CAAC;EACrC;AACJ;AAEA,OAAO,MAAMC,4BAA4B,GAAGxC,cAAc,CAACyC,oBAAoB,CAAC;EAC5EC,cAAc,EAAEzC,kBAAkB;EAClC0C,YAAY,EAAE;AAClB,CAAC,CAAC","ignoreList":[]}
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { FileAfterCreateEventHandler } from "@webiny/api-file-manager/features/file/CreateFile/events.js";
|
|
2
2
|
import { TaskService } from "@webiny/api-core/features/task/TaskService/index.js";
|
|
3
|
-
declare class ExtractMetadataHandlerImpl implements
|
|
3
|
+
declare class ExtractMetadataHandlerImpl implements FileAfterCreateEventHandler.Interface {
|
|
4
4
|
private taskService;
|
|
5
5
|
constructor(taskService: TaskService.Interface);
|
|
6
|
-
handle(event:
|
|
6
|
+
handle(event: FileAfterCreateEventHandler.Event): Promise<void>;
|
|
7
7
|
}
|
|
8
8
|
export declare const ExtractMetadataHandler: typeof ExtractMetadataHandlerImpl & {
|
|
9
|
-
__abstraction: import("@webiny/di").Abstraction<import("@webiny/api-core/features/
|
|
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
10
|
};
|
|
11
11
|
export {};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { FileAfterCreateEventHandler } from "@webiny/api-file-manager/features/file/CreateFile/events.js";
|
|
2
2
|
import { TaskService } from "@webiny/api-core/features/task/TaskService/index.js";
|
|
3
3
|
class ExtractMetadataHandlerImpl {
|
|
4
4
|
constructor(taskService) {
|
|
@@ -18,7 +18,7 @@ class ExtractMetadataHandlerImpl {
|
|
|
18
18
|
});
|
|
19
19
|
}
|
|
20
20
|
}
|
|
21
|
-
export const ExtractMetadataHandler =
|
|
21
|
+
export const ExtractMetadataHandler = FileAfterCreateEventHandler.createImplementation({
|
|
22
22
|
implementation: ExtractMetadataHandlerImpl,
|
|
23
23
|
dependencies: [TaskService]
|
|
24
24
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["
|
|
1
|
+
{"version":3,"names":["FileAfterCreateEventHandler","TaskService","ExtractMetadataHandlerImpl","constructor","taskService","handle","event","file","payload","trigger","definition","input","fileId","id","ExtractMetadataHandler","createImplementation","implementation","dependencies"],"sources":["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"],"mappings":"AAAA,SAASA,2BAA2B,QAAQ,6DAA6D;AACzG,SAASC,WAAW,QAAQ,qDAAqD;AAGjF,MAAMC,0BAA0B,CAAkD;EAC9EC,WAAWA,CAASC,WAAkC,EAAE;IAAA,KAApCA,WAAkC,GAAlCA,WAAkC;EAAG;EAEzD,MAAMC,MAAMA,CAACC,KAAwC,EAAiB;IAClE,MAAM;MAAEC;IAAK,CAAC,GAAGD,KAAK,CAACE,OAAO;;IAE9B;IACA,MAAM,IAAI,CAACJ,WAAW,CAACK,OAAO,CAAuB;MACjDC,UAAU,EAAE,4BAA4B;MACxCC,KAAK,EAAE;QACHC,MAAM,EAAEL,IAAI,CAACM;MACjB;IACJ,CAAC,CAAC;EACN;AACJ;AAEA,OAAO,MAAMC,sBAAsB,GAAGd,2BAA2B,CAACe,oBAAoB,CAAC;EACnFC,cAAc,EAAEd,0BAA0B;EAC1Ce,YAAY,EAAE,CAAChB,WAAW;AAC9B,CAAC,CAAC","ignoreList":[]}
|
|
@@ -13,6 +13,7 @@ declare class ExtractMetadataTask implements TaskDefinition.Interface<ExtractMet
|
|
|
13
13
|
maxIterations: number;
|
|
14
14
|
isPrivate: boolean;
|
|
15
15
|
databaseLogs: boolean;
|
|
16
|
+
selfCleanup: ("onSuccess" | "onAbort")[];
|
|
16
17
|
constructor(keyValueStore: GlobalKeyValueStore.Interface, updateFileUseCase: UpdateFileUseCase.Interface);
|
|
17
18
|
run({ input, controller }: TaskDefinition.RunParams<ExtractMetadataInput>): Promise<TaskDefinition.Result<ExtractMetadataInput>>;
|
|
18
19
|
private cleanValues;
|
|
@@ -10,6 +10,7 @@ class ExtractMetadataTask {
|
|
|
10
10
|
maxIterations = 1;
|
|
11
11
|
isPrivate = true;
|
|
12
12
|
databaseLogs = false;
|
|
13
|
+
selfCleanup = ["onSuccess", "onAbort"];
|
|
13
14
|
constructor(keyValueStore, updateFileUseCase) {
|
|
14
15
|
this.keyValueStore = keyValueStore;
|
|
15
16
|
this.updateFileUseCase = updateFileUseCase;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["S3","TaskDefinition","GlobalKeyValueStore","UpdateFileUseCase","MetadataReader","ExtractMetadataTask","id","title","description","maxIterations","isPrivate","databaseLogs","constructor","keyValueStore","updateFileUseCase","run","input","controller","runtime","isAborted","response","aborted","metadataReader","fileMetadata","read","fileId","error","message","contentType","startsWith","done","s3","bucket","String","process","env","S3_BUCKET","s3Object","getObject","Bucket","Key","bucketKey","Body","sharp","then","m","default","ExifReader","buffer","Buffer","from","transformToByteArray","sharpInstance","sharpMetadata","metadata","tags","load","expanded","image","width","height","format","orientation","exif","cleanValues","iptc","updateResult","execute","isFail","Error","cleaned","key","tag","Object","entries","undefined","Array","isArray","value","length","ExtractMetadataTaskDefinition","createImplementation","implementation","dependencies"],"sources":["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 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"],"mappings":"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","ignoreList":[]}
|
|
1
|
+
{"version":3,"names":["S3","TaskDefinition","GlobalKeyValueStore","UpdateFileUseCase","MetadataReader","ExtractMetadataTask","id","title","description","maxIterations","isPrivate","databaseLogs","selfCleanup","constructor","keyValueStore","updateFileUseCase","run","input","controller","runtime","isAborted","response","aborted","metadataReader","fileMetadata","read","fileId","error","message","contentType","startsWith","done","s3","bucket","String","process","env","S3_BUCKET","s3Object","getObject","Bucket","Key","bucketKey","Body","sharp","then","m","default","ExifReader","buffer","Buffer","from","transformToByteArray","sharpInstance","sharpMetadata","metadata","tags","load","expanded","image","width","height","format","orientation","exif","cleanValues","iptc","updateResult","execute","isFail","Error","cleaned","key","tag","Object","entries","undefined","Array","isArray","value","length","ExtractMetadataTaskDefinition","createImplementation","implementation","dependencies"],"sources":["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"],"mappings":"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","ignoreList":[]}
|
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { FileAfterDeleteEventHandler } from "@webiny/api-file-manager/features/file/DeleteFile/events.js";
|
|
2
2
|
import { TaskService } from "@webiny/api-core/features/task/TaskService/index.js";
|
|
3
|
-
declare class FlushCacheOnFileDeleteHandlerImpl implements
|
|
3
|
+
declare class FlushCacheOnFileDeleteHandlerImpl implements FileAfterDeleteEventHandler.Interface {
|
|
4
4
|
private taskService;
|
|
5
5
|
private readonly pathsGenerator;
|
|
6
6
|
constructor(taskService: TaskService.Interface);
|
|
7
|
-
handle(event:
|
|
7
|
+
handle(event: FileAfterDeleteEventHandler.Event): Promise<void>;
|
|
8
8
|
}
|
|
9
9
|
export declare const FlushCacheOnFileDeleteHandler: typeof FlushCacheOnFileDeleteHandlerImpl & {
|
|
10
|
-
__abstraction: import("@webiny/di").Abstraction<import("@webiny/api-core/features/
|
|
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
11
|
};
|
|
12
12
|
export {};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { FileAfterDeleteEventHandler } from "@webiny/api-file-manager/features/file/DeleteFile/events.js";
|
|
2
2
|
import { TaskService } from "@webiny/api-core/features/task/TaskService/index.js";
|
|
3
3
|
import { CdnPathsGenerator } from "../../utils/CdnPathsGenerator.js";
|
|
4
4
|
class FlushCacheOnFileDeleteHandlerImpl {
|
|
@@ -19,7 +19,7 @@ class FlushCacheOnFileDeleteHandlerImpl {
|
|
|
19
19
|
});
|
|
20
20
|
}
|
|
21
21
|
}
|
|
22
|
-
export const FlushCacheOnFileDeleteHandler =
|
|
22
|
+
export const FlushCacheOnFileDeleteHandler = FileAfterDeleteEventHandler.createImplementation({
|
|
23
23
|
implementation: FlushCacheOnFileDeleteHandlerImpl,
|
|
24
24
|
dependencies: [TaskService]
|
|
25
25
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["
|
|
1
|
+
{"version":3,"names":["FileAfterDeleteEventHandler","TaskService","CdnPathsGenerator","FlushCacheOnFileDeleteHandlerImpl","constructor","taskService","pathsGenerator","handle","event","file","payload","trigger","definition","input","caller","paths","generate","id","FlushCacheOnFileDeleteHandler","createImplementation","implementation","dependencies"],"sources":["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"],"mappings":"AAAA,SAASA,2BAA2B,QAAQ,6DAA6D;AACzG,SAASC,WAAW,QAAQ,qDAAqD;AACjF,SAASC,iBAAiB;AAE1B,MAAMC,iCAAiC,CAAkD;EAGrFC,WAAWA,CAASC,WAAkC,EAAE;IAAA,KAApCA,WAAkC,GAAlCA,WAAkC;IAClD,IAAI,CAACC,cAAc,GAAG,IAAIJ,iBAAiB,CAAC,CAAC;EACjD;EAEA,MAAMK,MAAMA,CAACC,KAAwC,EAAiB;IAClE,MAAM;MAAEC;IAAK,CAAC,GAAGD,KAAK,CAACE,OAAO;IAE9B,MAAM,IAAI,CAACL,WAAW,CAACM,OAAO,CAAC;MAC3BC,UAAU,EAAE,2BAA2B;MACvCC,KAAK,EAAE;QACHC,MAAM,EAAE,kBAAkB;QAC1BC,KAAK,EAAE,IAAI,CAACT,cAAc,CAACU,QAAQ,CAACP,IAAI,CAACQ,EAAE;MAC/C;IACJ,CAAC,CAAC;EACN;AACJ;AAEA,OAAO,MAAMC,6BAA6B,GAAGlB,2BAA2B,CAACmB,oBAAoB,CAAC;EAC1FC,cAAc,EAAEjB,iCAAiC;EACjDkB,YAAY,EAAE,CAACpB,WAAW;AAC9B,CAAC,CAAC","ignoreList":[]}
|
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { FileBeforeUpdateEventHandler } from "@webiny/api-file-manager/features/file/UpdateFile/events.js";
|
|
2
2
|
import { TaskService } from "@webiny/api-core/features/task/TaskService/index.js";
|
|
3
|
-
declare class FlushCacheOnFileUpdateHandlerImpl implements
|
|
3
|
+
declare class FlushCacheOnFileUpdateHandlerImpl implements FileBeforeUpdateEventHandler.Interface {
|
|
4
4
|
private taskService;
|
|
5
5
|
private readonly pathsGenerator;
|
|
6
6
|
constructor(taskService: TaskService.Interface);
|
|
7
|
-
handle(event:
|
|
7
|
+
handle(event: FileBeforeUpdateEventHandler.Event): Promise<void>;
|
|
8
8
|
}
|
|
9
9
|
export declare const FlushCacheOnFileUpdateHandler: typeof FlushCacheOnFileUpdateHandlerImpl & {
|
|
10
|
-
__abstraction: import("@webiny/di").Abstraction<import("@webiny/api-core/features/
|
|
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
11
|
};
|
|
12
12
|
export {};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { FileBeforeUpdateEventHandler } from "@webiny/api-file-manager/features/file/UpdateFile/events.js";
|
|
2
2
|
import { TaskService } from "@webiny/api-core/features/task/TaskService/index.js";
|
|
3
3
|
import { CdnPathsGenerator } from "../../utils/CdnPathsGenerator.js";
|
|
4
4
|
class FlushCacheOnFileUpdateHandlerImpl {
|
|
@@ -27,7 +27,7 @@ class FlushCacheOnFileUpdateHandlerImpl {
|
|
|
27
27
|
});
|
|
28
28
|
}
|
|
29
29
|
}
|
|
30
|
-
export const FlushCacheOnFileUpdateHandler =
|
|
30
|
+
export const FlushCacheOnFileUpdateHandler = FileBeforeUpdateEventHandler.createImplementation({
|
|
31
31
|
implementation: FlushCacheOnFileUpdateHandlerImpl,
|
|
32
32
|
dependencies: [TaskService]
|
|
33
33
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["
|
|
1
|
+
{"version":3,"names":["FileBeforeUpdateEventHandler","TaskService","CdnPathsGenerator","FlushCacheOnFileUpdateHandlerImpl","constructor","taskService","pathsGenerator","handle","event","file","original","payload","prevAccessControl","accessControl","newAccessControl","type","trigger","definition","input","caller","paths","generate","id","FlushCacheOnFileUpdateHandler","createImplementation","implementation","dependencies"],"sources":["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"],"mappings":"AAAA,SAASA,4BAA4B,QAAQ,6DAA6D;AAC1G,SAASC,WAAW,QAAQ,qDAAqD;AACjF,SAASC,iBAAiB;AAE1B,MAAMC,iCAAiC,CAAmD;EAGtFC,WAAWA,CAASC,WAAkC,EAAE;IAAA,KAApCA,WAAkC,GAAlCA,WAAkC;IAClD,IAAI,CAACC,cAAc,GAAG,IAAIJ,iBAAiB,CAAC,CAAC;EACjD;EAEA,MAAMK,MAAMA,CAACC,KAAyC,EAAiB;IACnE,MAAM;MAAEC,IAAI;MAAEC;IAAS,CAAC,GAAGF,KAAK,CAACG,OAAO;IAExC,MAAMC,iBAAiB,GAAGF,QAAQ,CAACG,aAAa;IAChD,MAAMC,gBAAgB,GAAGL,IAAI,CAACI,aAAa;;IAE3C;IACA,IAAID,iBAAiB,EAAEG,IAAI,KAAKD,gBAAgB,EAAEC,IAAI,EAAE;MACpD;IACJ;IAEA,MAAM,IAAI,CAACV,WAAW,CAACW,OAAO,CAAC;MAC3BC,UAAU,EAAE,2BAA2B;MACvCC,KAAK,EAAE;QACHC,MAAM,EAAE,kBAAkB;QAC1BC,KAAK,EAAE,IAAI,CAACd,cAAc,CAACe,QAAQ,CAACZ,IAAI,CAACa,EAAE;MAC/C;IACJ,CAAC,CAAC;EACN;AACJ;AAEA,OAAO,MAAMC,6BAA6B,GAAGvB,4BAA4B,CAACwB,oBAAoB,CAAC;EAC3FC,cAAc,EAAEtB,iCAAiC;EACjDuB,YAAY,EAAE,CAACzB,WAAW;AAC9B,CAAC,CAAC","ignoreList":[]}
|
|
@@ -15,6 +15,7 @@ declare class InvalidateCloudfrontCacheTask implements TaskDefinition.Interface<
|
|
|
15
15
|
description: string;
|
|
16
16
|
maxIterations: number;
|
|
17
17
|
isPrivate: boolean;
|
|
18
|
+
selfCleanup: ("onSuccess" | "onAbort")[];
|
|
18
19
|
private continueIfCode;
|
|
19
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>>;
|
|
20
21
|
private invalidateCache;
|
|
@@ -9,6 +9,7 @@ class InvalidateCloudfrontCacheTask {
|
|
|
9
9
|
description = "A task to invalidate Cloudfront cache by given paths.";
|
|
10
10
|
maxIterations = 100;
|
|
11
11
|
isPrivate = true;
|
|
12
|
+
selfCleanup = ["onSuccess", "onAbort"];
|
|
12
13
|
continueIfCode = ["TooManyInvalidationsInProgress", "Throttling"];
|
|
13
14
|
async run({
|
|
14
15
|
input,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["ServiceDiscovery","CloudFront","TaskDefinition","executeWithRetry","ReturnContinue","Error","InvalidateCloudfrontCacheTask","id","title","description","maxIterations","isPrivate","continueIfCode","run","input","controller","runtime","isAborted","response","aborted","manifest","load","error","message","code","data","distributionId","api","cloudfront","invalidateCache","caller","paths","minTimeout","retries","onFailedAttempt","includes","name","isCloseToTimeout","continue","done","createInvalidation","DistributionId","InvalidationBatch","CallerReference","Date","getTime","Paths","Quantity","length","Items","InvalidateCloudfrontCacheTaskDefinition","createImplementation","implementation","dependencies"],"sources":["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 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"],"mappings":"AAAA,SAASA,gBAAgB,QAAQ,aAAa;AAC9C,SAASC,UAAU,QAAQ,4CAA4C;AACvE,SAASC,cAAc,QAAQ,wDAAwD;AACvF,SAASC,gBAAgB,QAAQ,eAAe;AAEhD,MAAMC,cAAc,SAASC,KAAK,CAAC;AAanC,MAAMC,6BAA6B,CAA2D;EAC1FC,EAAE,GAAG,2BAA2B;EAChCC,KAAK,GAAG,6BAA6B;EACrCC,WAAW,GAAG,uDAAuD;EACrEC,aAAa,GAAG,GAAG;EACnBC,SAAS,GAAG,IAAI;
|
|
1
|
+
{"version":3,"names":["ServiceDiscovery","CloudFront","TaskDefinition","executeWithRetry","ReturnContinue","Error","InvalidateCloudfrontCacheTask","id","title","description","maxIterations","isPrivate","selfCleanup","continueIfCode","run","input","controller","runtime","isAborted","response","aborted","manifest","load","error","message","code","data","distributionId","api","cloudfront","invalidateCache","caller","paths","minTimeout","retries","onFailedAttempt","includes","name","isCloseToTimeout","continue","done","createInvalidation","DistributionId","InvalidationBatch","CallerReference","Date","getTime","Paths","Quantity","length","Items","InvalidateCloudfrontCacheTaskDefinition","createImplementation","implementation","dependencies"],"sources":["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"],"mappings":"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","ignoreList":[]}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { Result } from "@webiny/feature/api";
|
|
2
|
+
import { GlobalKeyValueStore } from "@webiny/api-core/features/keyValueStore/index.js";
|
|
3
|
+
import { GetFileContentsUseCase } from "@webiny/api-file-manager/features/file/GetFileContents/index.js";
|
|
4
|
+
import type { FileContents } from "@webiny/api-file-manager/features/file/GetFileContents/index.js";
|
|
5
|
+
declare class GetFileContentsUseCaseImpl implements GetFileContentsUseCase.Interface {
|
|
6
|
+
private metadataReader;
|
|
7
|
+
constructor(keyValueStore: GlobalKeyValueStore.Interface);
|
|
8
|
+
execute(fileId: string): Promise<Result<FileContents, GetFileContentsUseCase.Error>>;
|
|
9
|
+
}
|
|
10
|
+
export declare const GetFileContentsUseCaseImplementation: typeof GetFileContentsUseCaseImpl & {
|
|
11
|
+
__abstraction: import("@webiny/di").Abstraction<import("@webiny/api-file-manager/features/file/GetFileContents/abstractions").IGetFileContentsUseCase>;
|
|
12
|
+
};
|
|
13
|
+
export {};
|
|
@@ -0,0 +1,41 @@
|
|
|
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 { GetFileContentsUseCase } from "@webiny/api-file-manager/features/file/GetFileContents/index.js";
|
|
5
|
+
import { FileNotFoundError, FilePersistenceError } from "@webiny/api-file-manager/domain/file/errors.js";
|
|
6
|
+
import { MetadataReader } from "../WriteFileMetadata/MetadataReader.js";
|
|
7
|
+
class GetFileContentsUseCaseImpl {
|
|
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) {
|
|
14
|
+
return Result.fail(new FileNotFoundError(fileId));
|
|
15
|
+
}
|
|
16
|
+
try {
|
|
17
|
+
const s3 = new S3();
|
|
18
|
+
const bucket = String(process.env.S3_BUCKET);
|
|
19
|
+
const response = await s3.getObject({
|
|
20
|
+
Bucket: bucket,
|
|
21
|
+
Key: metadata.bucketKey
|
|
22
|
+
});
|
|
23
|
+
if (!response.Body) {
|
|
24
|
+
return Result.fail(new FileNotFoundError(fileId));
|
|
25
|
+
}
|
|
26
|
+
const buffer = Buffer.from(await response.Body.transformToByteArray());
|
|
27
|
+
return Result.ok({
|
|
28
|
+
buffer,
|
|
29
|
+
contentType: metadata.contentType
|
|
30
|
+
});
|
|
31
|
+
} catch (error) {
|
|
32
|
+
return Result.fail(new FilePersistenceError(error instanceof Error ? error : new Error(String(error))));
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
export const GetFileContentsUseCaseImplementation = GetFileContentsUseCase.createImplementation({
|
|
37
|
+
implementation: GetFileContentsUseCaseImpl,
|
|
38
|
+
dependencies: [GlobalKeyValueStore]
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
//# sourceMappingURL=GetFileContentsUseCase.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["Result","S3","GlobalKeyValueStore","GetFileContentsUseCase","FileNotFoundError","FilePersistenceError","MetadataReader","GetFileContentsUseCaseImpl","constructor","keyValueStore","metadataReader","execute","fileId","metadata","read","fail","s3","bucket","String","process","env","S3_BUCKET","response","getObject","Bucket","Key","bucketKey","Body","buffer","Buffer","from","transformToByteArray","ok","contentType","error","Error","GetFileContentsUseCaseImplementation","createImplementation","implementation","dependencies"],"sources":["GetFileContentsUseCase.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 { GetFileContentsUseCase } from \"@webiny/api-file-manager/features/file/GetFileContents/index.js\";\nimport type { FileContents } from \"@webiny/api-file-manager/features/file/GetFileContents/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 GetFileContentsUseCaseImpl implements GetFileContentsUseCase.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, GetFileContentsUseCase.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 GetFileContentsUseCaseImplementation = GetFileContentsUseCase.createImplementation({\n implementation: GetFileContentsUseCaseImpl,\n dependencies: [GlobalKeyValueStore]\n});\n"],"mappings":"AAAA,SAASA,MAAM,QAAQ,qBAAqB;AAC5C,SAASC,EAAE,QAAQ,oCAAoC;AACvD,SAASC,mBAAmB,QAAQ,kDAAkD;AACtF,SAASC,sBAAsB,QAAQ,iEAAiE;AAExG,SACIC,iBAAiB,EACjBC,oBAAoB,QACjB,gDAAgD;AACvD,SAASC,cAAc;AAEvB,MAAMC,0BAA0B,CAA6C;EAGzEC,WAAWA,CAACC,aAA4C,EAAE;IACtD,IAAI,CAACC,cAAc,GAAG,IAAIJ,cAAc,CAACG,aAAa,CAAC;EAC3D;EAEA,MAAME,OAAOA,CAACC,MAAc,EAA+D;IACvF,MAAMC,QAAQ,GAAG,MAAM,IAAI,CAACH,cAAc,CAACI,IAAI,CAACF,MAAM,CAAC;IACvD,IAAI,CAACC,QAAQ,EAAE;MACX,OAAOb,MAAM,CAACe,IAAI,CAAC,IAAIX,iBAAiB,CAACQ,MAAM,CAAC,CAAC;IACrD;IAEA,IAAI;MACA,MAAMI,EAAE,GAAG,IAAIf,EAAE,CAAC,CAAC;MACnB,MAAMgB,MAAM,GAAGC,MAAM,CAACC,OAAO,CAACC,GAAG,CAACC,SAAS,CAAC;MAC5C,MAAMC,QAAQ,GAAG,MAAMN,EAAE,CAACO,SAAS,CAAC;QAAEC,MAAM,EAAEP,MAAM;QAAEQ,GAAG,EAAEZ,QAAQ,CAACa;MAAU,CAAC,CAAC;MAEhF,IAAI,CAACJ,QAAQ,CAACK,IAAI,EAAE;QAChB,OAAO3B,MAAM,CAACe,IAAI,CAAC,IAAIX,iBAAiB,CAACQ,MAAM,CAAC,CAAC;MACrD;MAEA,MAAMgB,MAAM,GAAGC,MAAM,CAACC,IAAI,CAAC,MAAMR,QAAQ,CAACK,IAAI,CAACI,oBAAoB,CAAC,CAAC,CAAC;MACtE,OAAO/B,MAAM,CAACgC,EAAE,CAAC;QAAEJ,MAAM;QAAEK,WAAW,EAAEpB,QAAQ,CAACoB;MAAY,CAAC,CAAC;IACnE,CAAC,CAAC,OAAOC,KAAK,EAAE;MACZ,OAAOlC,MAAM,CAACe,IAAI,CACd,IAAIV,oBAAoB,CAAC6B,KAAK,YAAYC,KAAK,GAAGD,KAAK,GAAG,IAAIC,KAAK,CAACjB,MAAM,CAACgB,KAAK,CAAC,CAAC,CACtF,CAAC;IACL;EACJ;AACJ;AAEA,OAAO,MAAME,oCAAoC,GAAGjC,sBAAsB,CAACkC,oBAAoB,CAAC;EAC5FC,cAAc,EAAE/B,0BAA0B;EAC1CgC,YAAY,EAAE,CAACrC,mBAAmB;AACtC,CAAC,CAAC","ignoreList":[]}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { createFeature } from "@webiny/feature/api";
|
|
2
|
+
import { GetFileContentsUseCaseImplementation } from "./GetFileContentsUseCase.js";
|
|
3
|
+
export const GetFileContentsFeature = createFeature({
|
|
4
|
+
name: "FileManagerS3/GetFileContents",
|
|
5
|
+
register(container) {
|
|
6
|
+
container.register(GetFileContentsUseCaseImplementation);
|
|
7
|
+
}
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
//# sourceMappingURL=feature.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["createFeature","GetFileContentsUseCaseImplementation","GetFileContentsFeature","name","register","container"],"sources":["feature.ts"],"sourcesContent":["import { createFeature } from \"@webiny/feature/api\";\nimport { GetFileContentsUseCaseImplementation } from \"./GetFileContentsUseCase.js\";\n\nexport const GetFileContentsFeature = createFeature({\n name: \"FileManagerS3/GetFileContents\",\n register(container) {\n container.register(GetFileContentsUseCaseImplementation);\n }\n});\n"],"mappings":"AAAA,SAASA,aAAa,QAAQ,qBAAqB;AACnD,SAASC,oCAAoC;AAE7C,OAAO,MAAMC,sBAAsB,GAAGF,aAAa,CAAC;EAChDG,IAAI,EAAE,+BAA+B;EACrCC,QAAQA,CAACC,SAAS,EAAE;IAChBA,SAAS,CAACD,QAAQ,CAACH,oCAAoC,CAAC;EAC5D;AACJ,CAAC,CAAC","ignoreList":[]}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { TenantContext } from "@webiny/api-core/features/TenantContext";
|
|
1
|
+
import { TenantContext } from "@webiny/api-core/features/tenancy/TenantContext/index.js";
|
|
2
2
|
import type { File } from "@webiny/api-file-manager/domain/file/types.js";
|
|
3
3
|
import { GlobalKeyValueStore } from "@webiny/api-core/features/keyValueStore/index.js";
|
|
4
4
|
export declare class MetadataWriter {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["MetadataWriter","constructor","tenantContext","keyValueStore","write","files","writers","map","file","metadata","getMetadata","set","id","Promise","all","tenant","getTenant","bucketKey","key","size","contentType","type"],"sources":["MetadataWriter.ts"],"sourcesContent":["import { TenantContext } from \"@webiny/api-core/features/TenantContext\";\nimport type { File } from \"@webiny/api-file-manager/domain/file/types.js\";\nimport { GlobalKeyValueStore } from \"@webiny/api-core/features/keyValueStore/index.js\";\n\nexport class MetadataWriter {\n constructor(\n private tenantContext: TenantContext.Interface,\n private keyValueStore: GlobalKeyValueStore.Interface\n ) {}\n\n async write(files: File[]) {\n /**\n * We need to write each file with retry.\n */\n const writers = files.map(async file => {\n const metadata = this.getMetadata(file);\n await this.keyValueStore.set(`FileManager/File/${file.id}/Metadata`, metadata);\n });\n\n await Promise.all(writers);\n }\n\n private getMetadata(file: File) {\n const tenant = this.tenantContext.getTenant();\n return {\n id: file.id,\n bucketKey: `tenants/${tenant.id}/files/${file.key}`,\n tenant: tenant.id,\n size: file.size,\n contentType: file.type\n };\n }\n}\n"],"mappings":"AAIA,OAAO,MAAMA,cAAc,CAAC;EACxBC,WAAWA,CACCC,aAAsC,EACtCC,aAA4C,EACtD;IAAA,KAFUD,aAAsC,GAAtCA,aAAsC;IAAA,KACtCC,aAA4C,GAA5CA,aAA4C;EACrD;EAEH,MAAMC,KAAKA,CAACC,KAAa,EAAE;IACvB;AACR;AACA;IACQ,MAAMC,OAAO,GAAGD,KAAK,CAACE,GAAG,CAAC,MAAMC,IAAI,IAAI;MACpC,MAAMC,QAAQ,GAAG,IAAI,CAACC,WAAW,CAACF,IAAI,CAAC;MACvC,MAAM,IAAI,CAACL,aAAa,CAACQ,GAAG,CAAC,oBAAoBH,IAAI,CAACI,EAAE,WAAW,EAAEH,QAAQ,CAAC;IAClF,CAAC,CAAC;IAEF,MAAMI,OAAO,CAACC,GAAG,CAACR,OAAO,CAAC;EAC9B;EAEQI,WAAWA,CAACF,IAAU,EAAE;IAC5B,MAAMO,MAAM,GAAG,IAAI,CAACb,aAAa,CAACc,SAAS,CAAC,CAAC;IAC7C,OAAO;MACHJ,EAAE,EAAEJ,IAAI,CAACI,EAAE;MACXK,SAAS,EAAE,WAAWF,MAAM,CAACH,EAAE,UAAUJ,IAAI,CAACU,GAAG,EAAE;MACnDH,MAAM,EAAEA,MAAM,CAACH,EAAE;MACjBO,IAAI,EAAEX,IAAI,CAACW,IAAI;MACfC,WAAW,EAAEZ,IAAI,CAACa;IACtB,CAAC;EACL;AACJ","ignoreList":[]}
|
|
1
|
+
{"version":3,"names":["MetadataWriter","constructor","tenantContext","keyValueStore","write","files","writers","map","file","metadata","getMetadata","set","id","Promise","all","tenant","getTenant","bucketKey","key","size","contentType","type"],"sources":["MetadataWriter.ts"],"sourcesContent":["import { TenantContext } from \"@webiny/api-core/features/tenancy/TenantContext/index.js\";\nimport type { File } from \"@webiny/api-file-manager/domain/file/types.js\";\nimport { GlobalKeyValueStore } from \"@webiny/api-core/features/keyValueStore/index.js\";\n\nexport class MetadataWriter {\n constructor(\n private tenantContext: TenantContext.Interface,\n private keyValueStore: GlobalKeyValueStore.Interface\n ) {}\n\n async write(files: File[]) {\n /**\n * We need to write each file with retry.\n */\n const writers = files.map(async file => {\n const metadata = this.getMetadata(file);\n await this.keyValueStore.set(`FileManager/File/${file.id}/Metadata`, metadata);\n });\n\n await Promise.all(writers);\n }\n\n private getMetadata(file: File) {\n const tenant = this.tenantContext.getTenant();\n return {\n id: file.id,\n bucketKey: `tenants/${tenant.id}/files/${file.key}`,\n tenant: tenant.id,\n size: file.size,\n contentType: file.type\n };\n }\n}\n"],"mappings":"AAIA,OAAO,MAAMA,cAAc,CAAC;EACxBC,WAAWA,CACCC,aAAsC,EACtCC,aAA4C,EACtD;IAAA,KAFUD,aAAsC,GAAtCA,aAAsC;IAAA,KACtCC,aAA4C,GAA5CA,aAA4C;EACrD;EAEH,MAAMC,KAAKA,CAACC,KAAa,EAAE;IACvB;AACR;AACA;IACQ,MAAMC,OAAO,GAAGD,KAAK,CAACE,GAAG,CAAC,MAAMC,IAAI,IAAI;MACpC,MAAMC,QAAQ,GAAG,IAAI,CAACC,WAAW,CAACF,IAAI,CAAC;MACvC,MAAM,IAAI,CAACL,aAAa,CAACQ,GAAG,CAAC,oBAAoBH,IAAI,CAACI,EAAE,WAAW,EAAEH,QAAQ,CAAC;IAClF,CAAC,CAAC;IAEF,MAAMI,OAAO,CAACC,GAAG,CAACR,OAAO,CAAC;EAC9B;EAEQI,WAAWA,CAACF,IAAU,EAAE;IAC5B,MAAMO,MAAM,GAAG,IAAI,CAACb,aAAa,CAACc,SAAS,CAAC,CAAC;IAC7C,OAAO;MACHJ,EAAE,EAAEJ,IAAI,CAACI,EAAE;MACXK,SAAS,EAAE,WAAWF,MAAM,CAACH,EAAE,UAAUJ,IAAI,CAACU,GAAG,EAAE;MACnDH,MAAM,EAAEA,MAAM,CAACH,EAAE;MACjBO,IAAI,EAAEX,IAAI,CAACW,IAAI;MACfC,WAAW,EAAEZ,IAAI,CAACa;IACtB,CAAC;EACL;AACJ","ignoreList":[]}
|
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
import { TenantContext } from "@webiny/api-core/features/TenantContext";
|
|
2
|
-
import {
|
|
1
|
+
import { TenantContext } from "@webiny/api-core/features/tenancy/TenantContext/index.js";
|
|
2
|
+
import { FileAfterBatchCreateEventHandler } from "@webiny/api-file-manager/features/file/CreateFilesInBatch/events.js";
|
|
3
3
|
import { GlobalKeyValueStore } from "@webiny/api-core/features/keyValueStore/index.js";
|
|
4
|
-
declare class WriteMetadataAfterBatchCreateHandlerImpl implements
|
|
4
|
+
declare class WriteMetadataAfterBatchCreateHandlerImpl implements FileAfterBatchCreateEventHandler.Interface {
|
|
5
5
|
private readonly metadataWriter;
|
|
6
6
|
constructor(tenantContext: TenantContext.Interface, keyValueStore: GlobalKeyValueStore.Interface);
|
|
7
|
-
handle(event:
|
|
7
|
+
handle(event: FileAfterBatchCreateEventHandler.Event): Promise<void>;
|
|
8
8
|
}
|
|
9
9
|
export declare const WriteMetadataAfterBatchCreateHandler: typeof WriteMetadataAfterBatchCreateHandlerImpl & {
|
|
10
|
-
__abstraction: import("@webiny/di").Abstraction<import("@webiny/api-core/features/
|
|
10
|
+
__abstraction: import("@webiny/di").Abstraction<import("@webiny/api-core/features/eventPublisher/abstractions.js").IEventHandler<import("@webiny/api-file-manager/features/file/CreateFilesInBatch/events.js").FileAfterBatchCreateEvent>>;
|
|
11
11
|
};
|
|
12
12
|
export {};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { TenantContext } from "@webiny/api-core/features/TenantContext";
|
|
2
|
-
import {
|
|
1
|
+
import { TenantContext } from "@webiny/api-core/features/tenancy/TenantContext/index.js";
|
|
2
|
+
import { FileAfterBatchCreateEventHandler } from "@webiny/api-file-manager/features/file/CreateFilesInBatch/events.js";
|
|
3
3
|
import { MetadataWriter } from "./MetadataWriter.js";
|
|
4
4
|
import { GlobalKeyValueStore } from "@webiny/api-core/features/keyValueStore/index.js";
|
|
5
5
|
class WriteMetadataAfterBatchCreateHandlerImpl {
|
|
@@ -13,7 +13,7 @@ class WriteMetadataAfterBatchCreateHandlerImpl {
|
|
|
13
13
|
await this.metadataWriter.write(files);
|
|
14
14
|
}
|
|
15
15
|
}
|
|
16
|
-
export const WriteMetadataAfterBatchCreateHandler =
|
|
16
|
+
export const WriteMetadataAfterBatchCreateHandler = FileAfterBatchCreateEventHandler.createImplementation({
|
|
17
17
|
implementation: WriteMetadataAfterBatchCreateHandlerImpl,
|
|
18
18
|
dependencies: [TenantContext, GlobalKeyValueStore]
|
|
19
19
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["TenantContext","
|
|
1
|
+
{"version":3,"names":["TenantContext","FileAfterBatchCreateEventHandler","MetadataWriter","GlobalKeyValueStore","WriteMetadataAfterBatchCreateHandlerImpl","constructor","tenantContext","keyValueStore","metadataWriter","handle","event","files","payload","write","WriteMetadataAfterBatchCreateHandler","createImplementation","implementation","dependencies"],"sources":["WriteMetadataAfterBatchCreateHandler.ts"],"sourcesContent":["import { TenantContext } from \"@webiny/api-core/features/tenancy/TenantContext/index.js\";\nimport { FileAfterBatchCreateEventHandler } from \"@webiny/api-file-manager/features/file/CreateFilesInBatch/events.js\";\nimport { MetadataWriter } from \"./MetadataWriter.js\";\nimport { GlobalKeyValueStore } from \"@webiny/api-core/features/keyValueStore/index.js\";\n\nclass WriteMetadataAfterBatchCreateHandlerImpl\n implements FileAfterBatchCreateEventHandler.Interface\n{\n private readonly metadataWriter: MetadataWriter;\n\n constructor(\n tenantContext: TenantContext.Interface,\n keyValueStore: GlobalKeyValueStore.Interface\n ) {\n this.metadataWriter = new MetadataWriter(tenantContext, keyValueStore);\n }\n\n async handle(event: FileAfterBatchCreateEventHandler.Event): Promise<void> {\n const { files } = event.payload;\n await this.metadataWriter.write(files);\n }\n}\n\nexport const WriteMetadataAfterBatchCreateHandler =\n FileAfterBatchCreateEventHandler.createImplementation({\n implementation: WriteMetadataAfterBatchCreateHandlerImpl,\n dependencies: [TenantContext, GlobalKeyValueStore]\n });\n"],"mappings":"AAAA,SAASA,aAAa,QAAQ,0DAA0D;AACxF,SAASC,gCAAgC,QAAQ,qEAAqE;AACtH,SAASC,cAAc;AACvB,SAASC,mBAAmB,QAAQ,kDAAkD;AAEtF,MAAMC,wCAAwC,CAE9C;EAGIC,WAAWA,CACPC,aAAsC,EACtCC,aAA4C,EAC9C;IACE,IAAI,CAACC,cAAc,GAAG,IAAIN,cAAc,CAACI,aAAa,EAAEC,aAAa,CAAC;EAC1E;EAEA,MAAME,MAAMA,CAACC,KAA6C,EAAiB;IACvE,MAAM;MAAEC;IAAM,CAAC,GAAGD,KAAK,CAACE,OAAO;IAC/B,MAAM,IAAI,CAACJ,cAAc,CAACK,KAAK,CAACF,KAAK,CAAC;EAC1C;AACJ;AAEA,OAAO,MAAMG,oCAAoC,GAC7Cb,gCAAgC,CAACc,oBAAoB,CAAC;EAClDC,cAAc,EAAEZ,wCAAwC;EACxDa,YAAY,EAAE,CAACjB,aAAa,EAAEG,mBAAmB;AACrD,CAAC,CAAC","ignoreList":[]}
|
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { FileAfterCreateEventHandler } from "@webiny/api-file-manager/features/file/CreateFile/events.js";
|
|
2
2
|
import { TenantContext } from "@webiny/api-core/features/tenancy/TenantContext/index.js";
|
|
3
3
|
import { GlobalKeyValueStore } from "@webiny/api-core/features/keyValueStore/index.js";
|
|
4
|
-
declare class WriteMetadataAfterCreateHandlerImpl implements
|
|
4
|
+
declare class WriteMetadataAfterCreateHandlerImpl implements FileAfterCreateEventHandler.Interface {
|
|
5
5
|
private readonly metadataWriter;
|
|
6
6
|
constructor(tenantContext: TenantContext.Interface, keyValueStore: GlobalKeyValueStore.Interface);
|
|
7
|
-
handle(event:
|
|
7
|
+
handle(event: FileAfterCreateEventHandler.Event): Promise<void>;
|
|
8
8
|
}
|
|
9
9
|
export declare const WriteMetadataAfterCreateHandler: typeof WriteMetadataAfterCreateHandlerImpl & {
|
|
10
|
-
__abstraction: import("@webiny/di").Abstraction<import("@webiny/api-core/features/
|
|
10
|
+
__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>>;
|
|
11
11
|
};
|
|
12
12
|
export {};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { FileAfterCreateEventHandler } from "@webiny/api-file-manager/features/file/CreateFile/events.js";
|
|
2
2
|
import { MetadataWriter } from "./MetadataWriter.js";
|
|
3
3
|
import { TenantContext } from "@webiny/api-core/features/tenancy/TenantContext/index.js";
|
|
4
4
|
import { GlobalKeyValueStore } from "@webiny/api-core/features/keyValueStore/index.js";
|
|
@@ -13,7 +13,7 @@ class WriteMetadataAfterCreateHandlerImpl {
|
|
|
13
13
|
await this.metadataWriter.write([file]);
|
|
14
14
|
}
|
|
15
15
|
}
|
|
16
|
-
export const WriteMetadataAfterCreateHandler =
|
|
16
|
+
export const WriteMetadataAfterCreateHandler = FileAfterCreateEventHandler.createImplementation({
|
|
17
17
|
implementation: WriteMetadataAfterCreateHandlerImpl,
|
|
18
18
|
dependencies: [TenantContext, GlobalKeyValueStore]
|
|
19
19
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["
|
|
1
|
+
{"version":3,"names":["FileAfterCreateEventHandler","MetadataWriter","TenantContext","GlobalKeyValueStore","WriteMetadataAfterCreateHandlerImpl","constructor","tenantContext","keyValueStore","metadataWriter","handle","event","file","payload","write","WriteMetadataAfterCreateHandler","createImplementation","implementation","dependencies"],"sources":["WriteMetadataAfterCreateHandler.ts"],"sourcesContent":["import { FileAfterCreateEventHandler } from \"@webiny/api-file-manager/features/file/CreateFile/events.js\";\nimport { MetadataWriter } from \"./MetadataWriter.js\";\nimport { TenantContext } from \"@webiny/api-core/features/tenancy/TenantContext/index.js\";\nimport { GlobalKeyValueStore } from \"@webiny/api-core/features/keyValueStore/index.js\";\n\nclass WriteMetadataAfterCreateHandlerImpl implements FileAfterCreateEventHandler.Interface {\n private readonly metadataWriter: MetadataWriter;\n\n constructor(\n tenantContext: TenantContext.Interface,\n keyValueStore: GlobalKeyValueStore.Interface\n ) {\n this.metadataWriter = new MetadataWriter(tenantContext, keyValueStore);\n }\n\n async handle(event: FileAfterCreateEventHandler.Event): Promise<void> {\n const { file } = event.payload;\n await this.metadataWriter.write([file]);\n }\n}\n\nexport const WriteMetadataAfterCreateHandler = FileAfterCreateEventHandler.createImplementation({\n implementation: WriteMetadataAfterCreateHandlerImpl,\n dependencies: [TenantContext, GlobalKeyValueStore]\n});\n"],"mappings":"AAAA,SAASA,2BAA2B,QAAQ,6DAA6D;AACzG,SAASC,cAAc;AACvB,SAASC,aAAa,QAAQ,0DAA0D;AACxF,SAASC,mBAAmB,QAAQ,kDAAkD;AAEtF,MAAMC,mCAAmC,CAAkD;EAGvFC,WAAWA,CACPC,aAAsC,EACtCC,aAA4C,EAC9C;IACE,IAAI,CAACC,cAAc,GAAG,IAAIP,cAAc,CAACK,aAAa,EAAEC,aAAa,CAAC;EAC1E;EAEA,MAAME,MAAMA,CAACC,KAAwC,EAAiB;IAClE,MAAM;MAAEC;IAAK,CAAC,GAAGD,KAAK,CAACE,OAAO;IAC9B,MAAM,IAAI,CAACJ,cAAc,CAACK,KAAK,CAAC,CAACF,IAAI,CAAC,CAAC;EAC3C;AACJ;AAEA,OAAO,MAAMG,+BAA+B,GAAGd,2BAA2B,CAACe,oBAAoB,CAAC;EAC5FC,cAAc,EAAEZ,mCAAmC;EACnDa,YAAY,EAAE,CAACf,aAAa,EAAEC,mBAAmB;AACrD,CAAC,CAAC","ignoreList":[]}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { FilePermission } from "@webiny/api-file-manager/types.js";
|
|
2
|
-
import { IdentityContext } from "@webiny/api-core/features/IdentityContext";
|
|
2
|
+
import { IdentityContext } from "@webiny/api-core/features/security/IdentityContext/index.js";
|
|
3
3
|
export declare const checkPermissions: (identityContext: IdentityContext.Interface, check?: {
|
|
4
4
|
rwd?: string;
|
|
5
5
|
}) => Promise<FilePermission[]>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["NotAuthorizedError","checkPermissions","identityContext","check","filePermissions","getPermissions","relevantFilePermissions","filter","current","rwd","hasRwd","length","filesFilePermissions","Array","isArray","permissionWithoutRwdRestrictions","some","permission","includes"],"sources":["checkPermissions.ts"],"sourcesContent":["import type { FilePermission } from \"@webiny/api-file-manager/types.js\";\nimport { NotAuthorizedError } from \"@webiny/api-core/features/security/shared/index.js\";\nimport { IdentityContext } from \"@webiny/api-core/features/IdentityContext\";\n\nexport const checkPermissions = async (\n identityContext: IdentityContext.Interface,\n check: { rwd?: string } = {}\n) => {\n const filePermissions = await identityContext.getPermissions<FilePermission>(\"fm.file\");\n\n const relevantFilePermissions = filePermissions.filter(current => {\n if (check.rwd && !hasRwd(current, check.rwd)) {\n return false;\n }\n\n return true;\n });\n\n if (relevantFilePermissions.length === 0) {\n throw new NotAuthorizedError();\n }\n\n return relevantFilePermissions;\n};\n\nconst hasRwd = (filesFilePermissions: FilePermission | FilePermission[], rwd: string): boolean => {\n if (!Array.isArray(filesFilePermissions)) {\n filesFilePermissions = [filesFilePermissions];\n }\n\n if (!rwd) {\n return true;\n }\n\n // Is there a permission that doesn't restrict RWD permissions, that means all RWD permissions are allowed.\n const permissionWithoutRwdRestrictions = filesFilePermissions.some(permission => {\n return typeof permission.rwd !== \"string\";\n });\n\n if (permissionWithoutRwdRestrictions) {\n return true;\n }\n\n // If there is no permission that doesn't restrict RWD permissions, that means we need to check if the RWD.\n return filesFilePermissions.some(permission => {\n return permission.rwd && permission.rwd.includes(rwd);\n });\n};\n"],"mappings":"AACA,SAASA,kBAAkB,QAAQ,oDAAoD;AAGvF,OAAO,MAAMC,gBAAgB,GAAG,MAAAA,CAC5BC,eAA0C,EAC1CC,KAAuB,GAAG,CAAC,CAAC,KAC3B;EACD,MAAMC,eAAe,GAAG,MAAMF,eAAe,CAACG,cAAc,CAAiB,SAAS,CAAC;EAEvF,MAAMC,uBAAuB,GAAGF,eAAe,CAACG,MAAM,CAACC,OAAO,IAAI;IAC9D,IAAIL,KAAK,CAACM,GAAG,IAAI,CAACC,MAAM,CAACF,OAAO,EAAEL,KAAK,CAACM,GAAG,CAAC,EAAE;MAC1C,OAAO,KAAK;IAChB;IAEA,OAAO,IAAI;EACf,CAAC,CAAC;EAEF,IAAIH,uBAAuB,CAACK,MAAM,KAAK,CAAC,EAAE;IACtC,MAAM,IAAIX,kBAAkB,CAAC,CAAC;EAClC;EAEA,OAAOM,uBAAuB;AAClC,CAAC;AAED,MAAMI,MAAM,GAAGA,CAACE,oBAAuD,EAAEH,GAAW,KAAc;EAC9F,IAAI,CAACI,KAAK,CAACC,OAAO,CAACF,oBAAoB,CAAC,EAAE;IACtCA,oBAAoB,GAAG,CAACA,oBAAoB,CAAC;EACjD;EAEA,IAAI,CAACH,GAAG,EAAE;IACN,OAAO,IAAI;EACf;;EAEA;EACA,MAAMM,gCAAgC,GAAGH,oBAAoB,CAACI,IAAI,CAACC,UAAU,IAAI;IAC7E,OAAO,OAAOA,UAAU,CAACR,GAAG,KAAK,QAAQ;EAC7C,CAAC,CAAC;EAEF,IAAIM,gCAAgC,EAAE;IAClC,OAAO,IAAI;EACf;;EAEA;EACA,OAAOH,oBAAoB,CAACI,IAAI,CAACC,UAAU,IAAI;IAC3C,OAAOA,UAAU,CAACR,GAAG,IAAIQ,UAAU,CAACR,GAAG,CAACS,QAAQ,CAACT,GAAG,CAAC;EACzD,CAAC,CAAC;AACN,CAAC","ignoreList":[]}
|
|
1
|
+
{"version":3,"names":["NotAuthorizedError","checkPermissions","identityContext","check","filePermissions","getPermissions","relevantFilePermissions","filter","current","rwd","hasRwd","length","filesFilePermissions","Array","isArray","permissionWithoutRwdRestrictions","some","permission","includes"],"sources":["checkPermissions.ts"],"sourcesContent":["import type { FilePermission } from \"@webiny/api-file-manager/types.js\";\nimport { NotAuthorizedError } from \"@webiny/api-core/features/security/shared/index.js\";\nimport { IdentityContext } from \"@webiny/api-core/features/security/IdentityContext/index.js\";\n\nexport const checkPermissions = async (\n identityContext: IdentityContext.Interface,\n check: { rwd?: string } = {}\n) => {\n const filePermissions = await identityContext.getPermissions<FilePermission>(\"fm.file\");\n\n const relevantFilePermissions = filePermissions.filter(current => {\n if (check.rwd && !hasRwd(current, check.rwd)) {\n return false;\n }\n\n return true;\n });\n\n if (relevantFilePermissions.length === 0) {\n throw new NotAuthorizedError();\n }\n\n return relevantFilePermissions;\n};\n\nconst hasRwd = (filesFilePermissions: FilePermission | FilePermission[], rwd: string): boolean => {\n if (!Array.isArray(filesFilePermissions)) {\n filesFilePermissions = [filesFilePermissions];\n }\n\n if (!rwd) {\n return true;\n }\n\n // Is there a permission that doesn't restrict RWD permissions, that means all RWD permissions are allowed.\n const permissionWithoutRwdRestrictions = filesFilePermissions.some(permission => {\n return typeof permission.rwd !== \"string\";\n });\n\n if (permissionWithoutRwdRestrictions) {\n return true;\n }\n\n // If there is no permission that doesn't restrict RWD permissions, that means we need to check if the RWD.\n return filesFilePermissions.some(permission => {\n return permission.rwd && permission.rwd.includes(rwd);\n });\n};\n"],"mappings":"AACA,SAASA,kBAAkB,QAAQ,oDAAoD;AAGvF,OAAO,MAAMC,gBAAgB,GAAG,MAAAA,CAC5BC,eAA0C,EAC1CC,KAAuB,GAAG,CAAC,CAAC,KAC3B;EACD,MAAMC,eAAe,GAAG,MAAMF,eAAe,CAACG,cAAc,CAAiB,SAAS,CAAC;EAEvF,MAAMC,uBAAuB,GAAGF,eAAe,CAACG,MAAM,CAACC,OAAO,IAAI;IAC9D,IAAIL,KAAK,CAACM,GAAG,IAAI,CAACC,MAAM,CAACF,OAAO,EAAEL,KAAK,CAACM,GAAG,CAAC,EAAE;MAC1C,OAAO,KAAK;IAChB;IAEA,OAAO,IAAI;EACf,CAAC,CAAC;EAEF,IAAIH,uBAAuB,CAACK,MAAM,KAAK,CAAC,EAAE;IACtC,MAAM,IAAIX,kBAAkB,CAAC,CAAC;EAClC;EAEA,OAAOM,uBAAuB;AAClC,CAAC;AAED,MAAMI,MAAM,GAAGA,CAACE,oBAAuD,EAAEH,GAAW,KAAc;EAC9F,IAAI,CAACI,KAAK,CAACC,OAAO,CAACF,oBAAoB,CAAC,EAAE;IACtCA,oBAAoB,GAAG,CAACA,oBAAoB,CAAC;EACjD;EAEA,IAAI,CAACH,GAAG,EAAE;IACN,OAAO,IAAI;EACf;;EAEA;EACA,MAAMM,gCAAgC,GAAGH,oBAAoB,CAACI,IAAI,CAACC,UAAU,IAAI;IAC7E,OAAO,OAAOA,UAAU,CAACR,GAAG,KAAK,QAAQ;EAC7C,CAAC,CAAC;EAEF,IAAIM,gCAAgC,EAAE;IAClC,OAAO,IAAI;EACf;;EAEA;EACA,OAAOH,oBAAoB,CAACI,IAAI,CAACC,UAAU,IAAI;IAC3C,OAAOA,UAAU,CAACR,GAAG,IAAIQ,UAAU,CAACR,GAAG,CAACS,QAAQ,CAACT,GAAG,CAAC;EACzD,CAAC,CAAC;AACN,CAAC","ignoreList":[]}
|
package/graphql/schema.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import pMap from "p-map";
|
|
2
2
|
import { createGraphQLSchemaPlugin } from "@webiny/handler-graphql";
|
|
3
|
-
import { IdentityContext } from "@webiny/api-core/features/IdentityContext";
|
|
3
|
+
import { IdentityContext } from "@webiny/api-core/features/security/IdentityContext/index.js";
|
|
4
4
|
import { S3 } from "@webiny/aws-sdk/client-s3/index.js";
|
|
5
5
|
import { ErrorResponse, Response } from "@webiny/handler-graphql/responses.js";
|
|
6
6
|
import { getPresignedPostPayload } from "../utils/getPresignedPostPayload.js";
|
package/graphql/schema.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["pMap","createGraphQLSchemaPlugin","IdentityContext","S3","ErrorResponse","Response","getPresignedPostPayload","checkPermissions","CreateMultiPartUploadUseCase","CompleteMultiPartUploadUseCase","createFileNormalizerFromContext","GetSettingsUseCase","TenantContext","createS3GraphQLSchema","typeDefs","resolvers","FmQuery","getPreSignedPostPayload","_","args","context","identityContext","container","resolve","getSettings","rwd","data","settingsResult","execute","settings","value","normalizer","presignedPayload","normalizeFile","e","message","code","getPreSignedPostPayloads","files","presignedPayloads","FmMutation","createMultiPartUpload","s3Client","region","process","env","AWS_REGION","useCase","String","S3_BUCKET","multiPartUpload","file","numberOfParts","completeMultiPartUpload","fileKey","uploadId"],"sources":["schema.ts"],"sourcesContent":["import pMap from \"p-map\";\nimport { createGraphQLSchemaPlugin } from \"@webiny/handler-graphql\";\nimport { IdentityContext } from \"@webiny/api-core/features/IdentityContext\";\nimport { S3 } from \"@webiny/aws-sdk/client-s3/index.js\";\nimport { ErrorResponse, Response } from \"@webiny/handler-graphql/responses.js\";\nimport { getPresignedPostPayload } from \"~/utils/getPresignedPostPayload.js\";\nimport { checkPermissions } from \"./checkPermissions.js\";\nimport type { PresignedPostPayloadData } from \"~/types.js\";\nimport { CreateMultiPartUploadUseCase } from \"~/multiPartUpload/CreateMultiPartUploadUseCase.js\";\nimport { CompleteMultiPartUploadUseCase } from \"~/multiPartUpload/CompleteMultiPartUploadUseCase.js\";\nimport { createFileNormalizerFromContext } from \"~/utils/createFileNormalizerFromContext.js\";\nimport { GetSettingsUseCase } from \"@webiny/api-file-manager/features/settings/GetSettings/abstractions.js\";\nimport { TenantContext } from \"@webiny/api-core/features/tenancy/TenantContext/index.js\";\n\nexport const createS3GraphQLSchema = () => {\n return createGraphQLSchemaPlugin({\n typeDefs: /* GraphQL */ `\n type UploadFileResponseDataFile {\n id: ID!\n name: String!\n type: String!\n size: Long!\n key: String!\n }\n\n input PreSignedPostPayloadInput {\n id: ID\n name: String!\n type: String!\n size: Long!\n key: String\n keyPrefix: String\n }\n\n type GetPreSignedPostPayloadResponseDataFile {\n id: ID!\n name: String!\n type: String!\n size: Long!\n key: String!\n }\n\n type GetPreSignedPostPayloadResponseData {\n # Contains data that is necessary for initiating a file upload.\n data: JSON!\n file: UploadFileResponseDataFile!\n }\n\n type GetPreSignedPostPayloadResponse {\n error: FmError\n data: GetPreSignedPostPayloadResponseData\n }\n\n type MultiPartUploadFilePart {\n partNumber: Int!\n url: String!\n }\n\n type CreateMultiPartUploadResponseData {\n file: GetPreSignedPostPayloadResponseDataFile!\n uploadId: String!\n parts: [MultiPartUploadFilePart!]!\n }\n\n type CompleteMultiPartUploadResponse {\n data: Boolean\n error: FmError\n }\n\n type GetPreSignedPostPayloadsResponse {\n error: FmError\n data: [GetPreSignedPostPayloadResponseData!]!\n }\n\n extend type FmQuery {\n getPreSignedPostPayload(\n data: PreSignedPostPayloadInput!\n ): GetPreSignedPostPayloadResponse\n getPreSignedPostPayloads(\n data: [PreSignedPostPayloadInput]!\n ): GetPreSignedPostPayloadsResponse\n }\n\n type CreateMultiPartUploadResponse {\n data: CreateMultiPartUploadResponseData\n error: FmError\n }\n\n input MultiPartUploadFilePartInput {\n partNumber: Int!\n etag: String!\n }\n\n extend type FmMutation {\n createMultiPartUpload(\n data: PreSignedPostPayloadInput!\n numberOfParts: Number!\n ): CreateMultiPartUploadResponse\n\n completeMultiPartUpload(\n fileKey: String!\n uploadId: String!\n ): CompleteMultiPartUploadResponse\n }\n `,\n resolvers: {\n FmQuery: {\n getPreSignedPostPayload: async (_, args: any, context) => {\n const identityContext = context.container.resolve(IdentityContext);\n const getSettings = context.container.resolve(GetSettingsUseCase);\n\n try {\n await checkPermissions(identityContext, { rwd: \"w\" });\n\n const data = args.data as PresignedPostPayloadData;\n\n const settingsResult = await getSettings.execute();\n const settings = settingsResult.value;\n\n const normalizer = createFileNormalizerFromContext(context);\n const presignedPayload = await getPresignedPostPayload(\n await normalizer.normalizeFile(data),\n settings,\n context.container.resolve(TenantContext)\n );\n\n return new Response(presignedPayload);\n } catch (e) {\n return new ErrorResponse({\n message: e.message,\n code: e.code,\n data: e.data\n });\n }\n },\n getPreSignedPostPayloads: async (_, args, context) => {\n const identityContext = context.container.resolve(IdentityContext);\n const getSettings = context.container.resolve(GetSettingsUseCase);\n await checkPermissions(identityContext, { rwd: \"w\" });\n\n const files = args.data as PresignedPostPayloadData[];\n\n try {\n const settingsResult = await getSettings.execute();\n const settings = settingsResult.value;\n\n const normalizer = createFileNormalizerFromContext(context);\n\n const presignedPayloads = await pMap(files, async data => {\n return getPresignedPostPayload(\n await normalizer.normalizeFile(data),\n settings,\n context.container.resolve(TenantContext)\n );\n });\n\n return new Response(presignedPayloads);\n } catch (e) {\n return new ErrorResponse({\n message: e.message,\n code: e.code,\n data: e.data\n });\n }\n }\n },\n FmMutation: {\n createMultiPartUpload: async (_, args, context) => {\n const identityContext = context.container.resolve(IdentityContext);\n await checkPermissions(identityContext, { rwd: \"w\" });\n\n const s3Client = new S3({\n region: process.env.AWS_REGION\n });\n\n try {\n const useCase = new CreateMultiPartUploadUseCase(\n String(process.env.S3_BUCKET),\n s3Client\n );\n\n const normalizer = createFileNormalizerFromContext(context);\n\n const multiPartUpload = await useCase.execute({\n file: await normalizer.normalizeFile(args.data),\n numberOfParts: args.numberOfParts\n });\n\n return new Response(multiPartUpload);\n } catch (e) {\n return new ErrorResponse({\n message: e.message,\n code: e.code,\n data: e.data\n });\n }\n },\n completeMultiPartUpload: async (_, args, context) => {\n const identityContext = context.container.resolve(IdentityContext);\n await checkPermissions(identityContext, { rwd: \"w\" });\n\n const s3Client = new S3({\n region: process.env.AWS_REGION\n });\n\n try {\n const useCase = new CompleteMultiPartUploadUseCase(\n String(process.env.S3_BUCKET),\n s3Client\n );\n\n await useCase.execute({\n fileKey: args.fileKey,\n uploadId: args.uploadId\n });\n\n return new Response(true);\n } catch (e) {\n return new ErrorResponse({\n message: e.message,\n code: e.code,\n data: e.data\n });\n }\n }\n }\n }\n });\n};\n"],"mappings":"AAAA,OAAOA,IAAI,MAAM,OAAO;AACxB,SAASC,yBAAyB,QAAQ,yBAAyB;AACnE,SAASC,eAAe,QAAQ,2CAA2C;AAC3E,SAASC,EAAE,QAAQ,oCAAoC;AACvD,SAASC,aAAa,EAAEC,QAAQ,QAAQ,sCAAsC;AAC9E,SAASC,uBAAuB;AAChC,SAASC,gBAAgB;AAEzB,SAASC,4BAA4B;AACrC,SAASC,8BAA8B;AACvC,SAASC,+BAA+B;AACxC,SAASC,kBAAkB,QAAQ,wEAAwE;AAC3G,SAASC,aAAa,QAAQ,0DAA0D;AAExF,OAAO,MAAMC,qBAAqB,GAAGA,CAAA,KAAM;EACvC,OAAOZ,yBAAyB,CAAC;IAC7Ba,QAAQ,EAAE,aAAc;AAChC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAAS;IACDC,SAAS,EAAE;MACPC,OAAO,EAAE;QACLC,uBAAuB,EAAE,MAAAA,CAAOC,CAAC,EAAEC,IAAS,EAAEC,OAAO,KAAK;UACtD,MAAMC,eAAe,GAAGD,OAAO,CAACE,SAAS,CAACC,OAAO,CAACrB,eAAe,CAAC;UAClE,MAAMsB,WAAW,GAAGJ,OAAO,CAACE,SAAS,CAACC,OAAO,CAACZ,kBAAkB,CAAC;UAEjE,IAAI;YACA,MAAMJ,gBAAgB,CAACc,eAAe,EAAE;cAAEI,GAAG,EAAE;YAAI,CAAC,CAAC;YAErD,MAAMC,IAAI,GAAGP,IAAI,CAACO,IAAgC;YAElD,MAAMC,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","ignoreList":[]}
|
|
1
|
+
{"version":3,"names":["pMap","createGraphQLSchemaPlugin","IdentityContext","S3","ErrorResponse","Response","getPresignedPostPayload","checkPermissions","CreateMultiPartUploadUseCase","CompleteMultiPartUploadUseCase","createFileNormalizerFromContext","GetSettingsUseCase","TenantContext","createS3GraphQLSchema","typeDefs","resolvers","FmQuery","getPreSignedPostPayload","_","args","context","identityContext","container","resolve","getSettings","rwd","data","settingsResult","execute","settings","value","normalizer","presignedPayload","normalizeFile","e","message","code","getPreSignedPostPayloads","files","presignedPayloads","FmMutation","createMultiPartUpload","s3Client","region","process","env","AWS_REGION","useCase","String","S3_BUCKET","multiPartUpload","file","numberOfParts","completeMultiPartUpload","fileKey","uploadId"],"sources":["schema.ts"],"sourcesContent":["import pMap from \"p-map\";\nimport { createGraphQLSchemaPlugin } from \"@webiny/handler-graphql\";\nimport { IdentityContext } from \"@webiny/api-core/features/security/IdentityContext/index.js\";\nimport { S3 } from \"@webiny/aws-sdk/client-s3/index.js\";\nimport { ErrorResponse, Response } from \"@webiny/handler-graphql/responses.js\";\nimport { getPresignedPostPayload } from \"~/utils/getPresignedPostPayload.js\";\nimport { checkPermissions } from \"./checkPermissions.js\";\nimport type { PresignedPostPayloadData } from \"~/types.js\";\nimport { CreateMultiPartUploadUseCase } from \"~/multiPartUpload/CreateMultiPartUploadUseCase.js\";\nimport { CompleteMultiPartUploadUseCase } from \"~/multiPartUpload/CompleteMultiPartUploadUseCase.js\";\nimport { createFileNormalizerFromContext } from \"~/utils/createFileNormalizerFromContext.js\";\nimport { GetSettingsUseCase } from \"@webiny/api-file-manager/features/settings/GetSettings/abstractions.js\";\nimport { TenantContext } from \"@webiny/api-core/features/tenancy/TenantContext/index.js\";\n\nexport const createS3GraphQLSchema = () => {\n return createGraphQLSchemaPlugin({\n typeDefs: /* GraphQL */ `\n type UploadFileResponseDataFile {\n id: ID!\n name: String!\n type: String!\n size: Long!\n key: String!\n }\n\n input PreSignedPostPayloadInput {\n id: ID\n name: String!\n type: String!\n size: Long!\n key: String\n keyPrefix: String\n }\n\n type GetPreSignedPostPayloadResponseDataFile {\n id: ID!\n name: String!\n type: String!\n size: Long!\n key: String!\n }\n\n type GetPreSignedPostPayloadResponseData {\n # Contains data that is necessary for initiating a file upload.\n data: JSON!\n file: UploadFileResponseDataFile!\n }\n\n type GetPreSignedPostPayloadResponse {\n error: FmError\n data: GetPreSignedPostPayloadResponseData\n }\n\n type MultiPartUploadFilePart {\n partNumber: Int!\n url: String!\n }\n\n type CreateMultiPartUploadResponseData {\n file: GetPreSignedPostPayloadResponseDataFile!\n uploadId: String!\n parts: [MultiPartUploadFilePart!]!\n }\n\n type CompleteMultiPartUploadResponse {\n data: Boolean\n error: FmError\n }\n\n type GetPreSignedPostPayloadsResponse {\n error: FmError\n data: [GetPreSignedPostPayloadResponseData!]!\n }\n\n extend type FmQuery {\n getPreSignedPostPayload(\n data: PreSignedPostPayloadInput!\n ): GetPreSignedPostPayloadResponse\n getPreSignedPostPayloads(\n data: [PreSignedPostPayloadInput]!\n ): GetPreSignedPostPayloadsResponse\n }\n\n type CreateMultiPartUploadResponse {\n data: CreateMultiPartUploadResponseData\n error: FmError\n }\n\n input MultiPartUploadFilePartInput {\n partNumber: Int!\n etag: String!\n }\n\n extend type FmMutation {\n createMultiPartUpload(\n data: PreSignedPostPayloadInput!\n numberOfParts: Number!\n ): CreateMultiPartUploadResponse\n\n completeMultiPartUpload(\n fileKey: String!\n uploadId: String!\n ): CompleteMultiPartUploadResponse\n }\n `,\n resolvers: {\n FmQuery: {\n getPreSignedPostPayload: async (_, args: any, context) => {\n const identityContext = context.container.resolve(IdentityContext);\n const getSettings = context.container.resolve(GetSettingsUseCase);\n\n try {\n await checkPermissions(identityContext, { rwd: \"w\" });\n\n const data = args.data as PresignedPostPayloadData;\n\n const settingsResult = await getSettings.execute();\n const settings = settingsResult.value;\n\n const normalizer = createFileNormalizerFromContext(context);\n const presignedPayload = await getPresignedPostPayload(\n await normalizer.normalizeFile(data),\n settings,\n context.container.resolve(TenantContext)\n );\n\n return new Response(presignedPayload);\n } catch (e) {\n return new ErrorResponse({\n message: e.message,\n code: e.code,\n data: e.data\n });\n }\n },\n getPreSignedPostPayloads: async (_, args, context) => {\n const identityContext = context.container.resolve(IdentityContext);\n const getSettings = context.container.resolve(GetSettingsUseCase);\n await checkPermissions(identityContext, { rwd: \"w\" });\n\n const files = args.data as PresignedPostPayloadData[];\n\n try {\n const settingsResult = await getSettings.execute();\n const settings = settingsResult.value;\n\n const normalizer = createFileNormalizerFromContext(context);\n\n const presignedPayloads = await pMap(files, async data => {\n return getPresignedPostPayload(\n await normalizer.normalizeFile(data),\n settings,\n context.container.resolve(TenantContext)\n );\n });\n\n return new Response(presignedPayloads);\n } catch (e) {\n return new ErrorResponse({\n message: e.message,\n code: e.code,\n data: e.data\n });\n }\n }\n },\n FmMutation: {\n createMultiPartUpload: async (_, args, context) => {\n const identityContext = context.container.resolve(IdentityContext);\n await checkPermissions(identityContext, { rwd: \"w\" });\n\n const s3Client = new S3({\n region: process.env.AWS_REGION\n });\n\n try {\n const useCase = new CreateMultiPartUploadUseCase(\n String(process.env.S3_BUCKET),\n s3Client\n );\n\n const normalizer = createFileNormalizerFromContext(context);\n\n const multiPartUpload = await useCase.execute({\n file: await normalizer.normalizeFile(args.data),\n numberOfParts: args.numberOfParts\n });\n\n return new Response(multiPartUpload);\n } catch (e) {\n return new ErrorResponse({\n message: e.message,\n code: e.code,\n data: e.data\n });\n }\n },\n completeMultiPartUpload: async (_, args, context) => {\n const identityContext = context.container.resolve(IdentityContext);\n await checkPermissions(identityContext, { rwd: \"w\" });\n\n const s3Client = new S3({\n region: process.env.AWS_REGION\n });\n\n try {\n const useCase = new CompleteMultiPartUploadUseCase(\n String(process.env.S3_BUCKET),\n s3Client\n );\n\n await useCase.execute({\n fileKey: args.fileKey,\n uploadId: args.uploadId\n });\n\n return new Response(true);\n } catch (e) {\n return new ErrorResponse({\n message: e.message,\n code: e.code,\n data: e.data\n });\n }\n }\n }\n }\n });\n};\n"],"mappings":"AAAA,OAAOA,IAAI,MAAM,OAAO;AACxB,SAASC,yBAAyB,QAAQ,yBAAyB;AACnE,SAASC,eAAe,QAAQ,6DAA6D;AAC7F,SAASC,EAAE,QAAQ,oCAAoC;AACvD,SAASC,aAAa,EAAEC,QAAQ,QAAQ,sCAAsC;AAC9E,SAASC,uBAAuB;AAChC,SAASC,gBAAgB;AAEzB,SAASC,4BAA4B;AACrC,SAASC,8BAA8B;AACvC,SAASC,+BAA+B;AACxC,SAASC,kBAAkB,QAAQ,wEAAwE;AAC3G,SAASC,aAAa,QAAQ,0DAA0D;AAExF,OAAO,MAAMC,qBAAqB,GAAGA,CAAA,KAAM;EACvC,OAAOZ,yBAAyB,CAAC;IAC7Ba,QAAQ,EAAE,aAAc;AAChC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAAS;IACDC,SAAS,EAAE;MACPC,OAAO,EAAE;QACLC,uBAAuB,EAAE,MAAAA,CAAOC,CAAC,EAAEC,IAAS,EAAEC,OAAO,KAAK;UACtD,MAAMC,eAAe,GAAGD,OAAO,CAACE,SAAS,CAACC,OAAO,CAACrB,eAAe,CAAC;UAClE,MAAMsB,WAAW,GAAGJ,OAAO,CAACE,SAAS,CAACC,OAAO,CAACZ,kBAAkB,CAAC;UAEjE,IAAI;YACA,MAAMJ,gBAAgB,CAACc,eAAe,EAAE;cAAEI,GAAG,EAAE;YAAI,CAAC,CAAC;YAErD,MAAMC,IAAI,GAAGP,IAAI,CAACO,IAAgC;YAElD,MAAMC,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","ignoreList":[]}
|
package/index.js
CHANGED
|
@@ -6,6 +6,7 @@ import { WriteFileMetadataFeature } from "./features/WriteFileMetadata/feature.j
|
|
|
6
6
|
import { ApplyThreatScanningFeature } from "./enterprise/ApplyThreatScanning/feature.js";
|
|
7
7
|
import { FlushCacheFeature } from "./features/FlushCache/feature.js";
|
|
8
8
|
import { ExtractMetadataFeature } from "./features/ExtractMetadata/feature.js";
|
|
9
|
+
import { GetFileContentsFeature } from "./features/GetFileContents/feature.js";
|
|
9
10
|
export { createFileUploadModifier } from "./utils/FileUploadModifier.js";
|
|
10
11
|
export { createAssetDelivery } from "./assetDelivery/createAssetDelivery.js";
|
|
11
12
|
const contextPlugin = new ContextPlugin(context => {
|
|
@@ -14,6 +15,7 @@ const contextPlugin = new ContextPlugin(context => {
|
|
|
14
15
|
DeleteFileFromBucketFeature.register(container);
|
|
15
16
|
ExtractMetadataFeature.register(container);
|
|
16
17
|
WriteFileMetadataFeature.register(container);
|
|
18
|
+
GetFileContentsFeature.register(container);
|
|
17
19
|
const wcp = container.resolve(WcpContext);
|
|
18
20
|
if (wcp.canUseFileManagerThreatDetection()) {
|
|
19
21
|
ApplyThreatScanningFeature.register(container);
|
package/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["ContextPlugin","WcpContext","createS3GraphQLSchema","DeleteFileFromBucketFeature","WriteFileMetadataFeature","ApplyThreatScanningFeature","FlushCacheFeature","ExtractMetadataFeature","createFileUploadModifier","createAssetDelivery","contextPlugin","context","container","register","wcp","resolve","canUseFileManagerThreatDetection","name","createFileManagerS3"],"sources":["index.ts"],"sourcesContent":["import { ContextPlugin } from \"@webiny/api\";\nimport { WcpContext } from \"@webiny/api-core/features/wcp/WcpContext/index.js\";\nimport { createS3GraphQLSchema } from \"./graphql/schema.js\";\nimport { DeleteFileFromBucketFeature } from \"~/features/DeleteFileFromBucket/feature.js\";\nimport { WriteFileMetadataFeature } from \"~/features/WriteFileMetadata/feature.js\";\nimport { ApplyThreatScanningFeature } from \"~/enterprise/ApplyThreatScanning/feature.js\";\nimport { FlushCacheFeature } from \"~/features/FlushCache/feature.js\";\nimport { ExtractMetadataFeature } from \"~/features/ExtractMetadata/feature.js\";\nexport { createFileUploadModifier } from \"./utils/FileUploadModifier.js\";\nexport { createAssetDelivery } from \"./assetDelivery/createAssetDelivery.js\";\n\nconst contextPlugin = new ContextPlugin(context => {\n const container = context.container;\n\n FlushCacheFeature.register(container);\n DeleteFileFromBucketFeature.register(container);\n ExtractMetadataFeature.register(container);\n WriteFileMetadataFeature.register(container);\n\n const wcp = container.resolve(WcpContext);\n if (wcp.canUseFileManagerThreatDetection()) {\n ApplyThreatScanningFeature.register(container);\n }\n});\n\ncontextPlugin.name = `fileManagerS3.context`;\n\nexport const createFileManagerS3 = () => [contextPlugin, createS3GraphQLSchema()];\n"],"mappings":"AAAA,SAASA,aAAa,QAAQ,aAAa;AAC3C,SAASC,UAAU,QAAQ,mDAAmD;AAC9E,SAASC,qBAAqB;AAC9B,SAASC,2BAA2B;AACpC,SAASC,wBAAwB;AACjC,SAASC,0BAA0B;AACnC,SAASC,iBAAiB;AAC1B,SAASC,sBAAsB;AAC/B,SAASC,wBAAwB;AACjC,SAASC,mBAAmB;AAE5B,MAAMC,aAAa,GAAG,
|
|
1
|
+
{"version":3,"names":["ContextPlugin","WcpContext","createS3GraphQLSchema","DeleteFileFromBucketFeature","WriteFileMetadataFeature","ApplyThreatScanningFeature","FlushCacheFeature","ExtractMetadataFeature","GetFileContentsFeature","createFileUploadModifier","createAssetDelivery","contextPlugin","context","container","register","wcp","resolve","canUseFileManagerThreatDetection","name","createFileManagerS3"],"sources":["index.ts"],"sourcesContent":["import { ContextPlugin } from \"@webiny/api\";\nimport { WcpContext } from \"@webiny/api-core/features/wcp/WcpContext/index.js\";\nimport { createS3GraphQLSchema } from \"./graphql/schema.js\";\nimport { DeleteFileFromBucketFeature } from \"~/features/DeleteFileFromBucket/feature.js\";\nimport { WriteFileMetadataFeature } from \"~/features/WriteFileMetadata/feature.js\";\nimport { ApplyThreatScanningFeature } from \"~/enterprise/ApplyThreatScanning/feature.js\";\nimport { FlushCacheFeature } from \"~/features/FlushCache/feature.js\";\nimport { ExtractMetadataFeature } from \"~/features/ExtractMetadata/feature.js\";\nimport { GetFileContentsFeature } from \"~/features/GetFileContents/feature.js\";\nexport { createFileUploadModifier } from \"./utils/FileUploadModifier.js\";\nexport { createAssetDelivery } from \"./assetDelivery/createAssetDelivery.js\";\n\nconst contextPlugin = new ContextPlugin(context => {\n const container = context.container;\n\n FlushCacheFeature.register(container);\n DeleteFileFromBucketFeature.register(container);\n ExtractMetadataFeature.register(container);\n WriteFileMetadataFeature.register(container);\n GetFileContentsFeature.register(container);\n\n const wcp = container.resolve(WcpContext);\n if (wcp.canUseFileManagerThreatDetection()) {\n ApplyThreatScanningFeature.register(container);\n }\n});\n\ncontextPlugin.name = `fileManagerS3.context`;\n\nexport const createFileManagerS3 = () => [contextPlugin, createS3GraphQLSchema()];\n"],"mappings":"AAAA,SAASA,aAAa,QAAQ,aAAa;AAC3C,SAASC,UAAU,QAAQ,mDAAmD;AAC9E,SAASC,qBAAqB;AAC9B,SAASC,2BAA2B;AACpC,SAASC,wBAAwB;AACjC,SAASC,0BAA0B;AACnC,SAASC,iBAAiB;AAC1B,SAASC,sBAAsB;AAC/B,SAASC,sBAAsB;AAC/B,SAASC,wBAAwB;AACjC,SAASC,mBAAmB;AAE5B,MAAMC,aAAa,GAAG,IAAIX,aAAa,CAACY,OAAO,IAAI;EAC/C,MAAMC,SAAS,GAAGD,OAAO,CAACC,SAAS;EAEnCP,iBAAiB,CAACQ,QAAQ,CAACD,SAAS,CAAC;EACrCV,2BAA2B,CAACW,QAAQ,CAACD,SAAS,CAAC;EAC/CN,sBAAsB,CAACO,QAAQ,CAACD,SAAS,CAAC;EAC1CT,wBAAwB,CAACU,QAAQ,CAACD,SAAS,CAAC;EAC5CL,sBAAsB,CAACM,QAAQ,CAACD,SAAS,CAAC;EAE1C,MAAME,GAAG,GAAGF,SAAS,CAACG,OAAO,CAACf,UAAU,CAAC;EACzC,IAAIc,GAAG,CAACE,gCAAgC,CAAC,CAAC,EAAE;IACxCZ,0BAA0B,CAACS,QAAQ,CAACD,SAAS,CAAC;EAClD;AACJ,CAAC,CAAC;AAEFF,aAAa,CAACO,IAAI,GAAG,uBAAuB;AAE5C,OAAO,MAAMC,mBAAmB,GAAGA,CAAA,KAAM,CAACR,aAAa,EAAET,qBAAqB,CAAC,CAAC,CAAC","ignoreList":[]}
|
package/package.json
CHANGED
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@webiny/api-file-manager-s3",
|
|
3
|
-
"version": "0.0.0-unstable.
|
|
3
|
+
"version": "0.0.0-unstable.e6f0dc8ca7",
|
|
4
4
|
"type": "module",
|
|
5
|
-
"
|
|
5
|
+
"exports": {
|
|
6
|
+
".": "./index.js",
|
|
7
|
+
"./*": "./*"
|
|
8
|
+
},
|
|
6
9
|
"repository": {
|
|
7
10
|
"type": "git",
|
|
8
11
|
"url": "https://github.com/webiny/webiny-js.git"
|
|
@@ -11,35 +14,36 @@
|
|
|
11
14
|
"author": "Webiny Ltd",
|
|
12
15
|
"license": "MIT",
|
|
13
16
|
"dependencies": {
|
|
14
|
-
"@webiny/api": "0.0.0-unstable.
|
|
15
|
-
"@webiny/api-core": "0.0.0-unstable.
|
|
16
|
-
"@webiny/api-file-manager": "0.0.0-unstable.
|
|
17
|
-
"@webiny/api-websockets": "0.0.0-unstable.
|
|
18
|
-
"@webiny/aws-sdk": "0.0.0-unstable.
|
|
19
|
-
"@webiny/feature": "0.0.0-unstable.
|
|
20
|
-
"@webiny/handler": "0.0.0-unstable.
|
|
21
|
-
"@webiny/handler-aws": "0.0.0-unstable.
|
|
22
|
-
"@webiny/handler-graphql": "0.0.0-unstable.
|
|
23
|
-
"@webiny/plugins": "0.0.0-unstable.
|
|
24
|
-
"@webiny/
|
|
25
|
-
"@webiny/
|
|
26
|
-
"
|
|
27
|
-
"
|
|
17
|
+
"@webiny/api": "0.0.0-unstable.e6f0dc8ca7",
|
|
18
|
+
"@webiny/api-core": "0.0.0-unstable.e6f0dc8ca7",
|
|
19
|
+
"@webiny/api-file-manager": "0.0.0-unstable.e6f0dc8ca7",
|
|
20
|
+
"@webiny/api-websockets": "0.0.0-unstable.e6f0dc8ca7",
|
|
21
|
+
"@webiny/aws-sdk": "0.0.0-unstable.e6f0dc8ca7",
|
|
22
|
+
"@webiny/feature": "0.0.0-unstable.e6f0dc8ca7",
|
|
23
|
+
"@webiny/handler": "0.0.0-unstable.e6f0dc8ca7",
|
|
24
|
+
"@webiny/handler-aws": "0.0.0-unstable.e6f0dc8ca7",
|
|
25
|
+
"@webiny/handler-graphql": "0.0.0-unstable.e6f0dc8ca7",
|
|
26
|
+
"@webiny/plugins": "0.0.0-unstable.e6f0dc8ca7",
|
|
27
|
+
"@webiny/tasks": "0.0.0-unstable.e6f0dc8ca7",
|
|
28
|
+
"@webiny/utils": "0.0.0-unstable.e6f0dc8ca7",
|
|
29
|
+
"@webiny/validation": "0.0.0-unstable.e6f0dc8ca7",
|
|
30
|
+
"exifreader": "4.38.1",
|
|
31
|
+
"mime": "4.1.0",
|
|
28
32
|
"object-hash": "3.0.0",
|
|
29
33
|
"p-map": "7.0.4",
|
|
30
34
|
"p-reduce": "3.0.0",
|
|
31
|
-
"sanitize-filename": "1.6.
|
|
35
|
+
"sanitize-filename": "1.6.4",
|
|
32
36
|
"sharp": "0.34.5"
|
|
33
37
|
},
|
|
34
38
|
"devDependencies": {
|
|
35
|
-
"@webiny/build-tools": "0.0.0-unstable.
|
|
36
|
-
"rimraf": "6.1.
|
|
37
|
-
"typescript": "
|
|
38
|
-
"vitest": "
|
|
39
|
+
"@webiny/build-tools": "0.0.0-unstable.e6f0dc8ca7",
|
|
40
|
+
"rimraf": "6.1.3",
|
|
41
|
+
"typescript": "6.0.3",
|
|
42
|
+
"vitest": "4.1.5"
|
|
39
43
|
},
|
|
40
44
|
"publishConfig": {
|
|
41
45
|
"access": "public",
|
|
42
46
|
"directory": "dist"
|
|
43
47
|
},
|
|
44
|
-
"gitHead": "
|
|
48
|
+
"gitHead": "e6f0dc8ca741c1fcc3fec9a5b9e86fdd49544641"
|
|
45
49
|
}
|
package/types.d.ts
CHANGED
package/types.js
CHANGED
package/types.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":[],"sources":["types.ts"],"sourcesContent":["import type { PresignedPost } from \"@webiny/aws-sdk/client-s3/index.js\";\n\nexport interface PresignedPostPayloadData {\n name: string;\n type: string;\n size: number;\n id?: string;\n key?: string;\n keyPrefix?: string;\n}\n\nexport interface FileData {\n id: string;\n key: string;\n name: string;\n size: number;\n type: string;\n}\n\nexport interface PresignedPostPayloadDataResponse {\n data: PresignedPost;\n file: FileData;\n}\n"],"mappings":"","ignoreList":[]}
|
|
1
|
+
{"version":3,"names":[],"sources":["types.ts"],"sourcesContent":["import type { PresignedPost } from \"@webiny/aws-sdk/client-s3/index.js\";\nimport \"@webiny/tasks/features/TaskController/augmentation.js\";\n\nexport interface PresignedPostPayloadData {\n name: string;\n type: string;\n size: number;\n id?: string;\n key?: string;\n keyPrefix?: string;\n}\n\nexport interface FileData {\n id: string;\n key: string;\n name: string;\n size: number;\n type: string;\n}\n\nexport interface PresignedPostPayloadDataResponse {\n data: PresignedPost;\n file: FileData;\n}\n"],"mappings":"AACA,OAAO,uDAAuD","ignoreList":[]}
|
package/utils/FileKey.test.js
CHANGED
|
@@ -15,7 +15,7 @@ describe("FileKey", () => {
|
|
|
15
15
|
name: "image-14",
|
|
16
16
|
type: "image/jpeg"
|
|
17
17
|
});
|
|
18
|
-
expect(fileKey.toString()).toEqual("image-14.
|
|
18
|
+
expect(fileKey.toString()).toEqual("image-14.jpg");
|
|
19
19
|
});
|
|
20
20
|
it("should generate a file key containing id", () => {
|
|
21
21
|
const fileKey = new FileKey({
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["describe","it","expect","FileKey","fileKey","size","name","type","toString","toEqual","id","keyPrefix","key"],"sources":["FileKey.test.ts"],"sourcesContent":["import { describe, it, expect } from \"vitest\";\nimport { FileKey } from \"./FileKey.js\";\n\ndescribe(\"FileKey\", () => {\n it(\"should generate a file key (extension is included in the name)\", () => {\n const fileKey = new FileKey({\n size: 1071690,\n name: \"image-14.jpg\",\n type: \"image/jpeg\"\n });\n\n expect(fileKey.toString()).toEqual(\"image-14.jpg\");\n });\n\n it(\"should generate a file key (extension derived from file type)\", () => {\n const fileKey = new FileKey({\n size: 1071690,\n name: \"image-14\",\n type: \"image/jpeg\"\n });\n\n expect(fileKey.toString()).toEqual(\"image-14.
|
|
1
|
+
{"version":3,"names":["describe","it","expect","FileKey","fileKey","size","name","type","toString","toEqual","id","keyPrefix","key"],"sources":["FileKey.test.ts"],"sourcesContent":["import { describe, it, expect } from \"vitest\";\nimport { FileKey } from \"./FileKey.js\";\n\ndescribe(\"FileKey\", () => {\n it(\"should generate a file key (extension is included in the name)\", () => {\n const fileKey = new FileKey({\n size: 1071690,\n name: \"image-14.jpg\",\n type: \"image/jpeg\"\n });\n\n expect(fileKey.toString()).toEqual(\"image-14.jpg\");\n });\n\n it(\"should generate a file key (extension derived from file type)\", () => {\n const fileKey = new FileKey({\n size: 1071690,\n name: \"image-14\",\n type: \"image/jpeg\"\n });\n\n expect(fileKey.toString()).toEqual(\"image-14.jpg\");\n });\n\n it(\"should generate a file key containing id\", () => {\n const fileKey = new FileKey({\n size: 1071690,\n name: \"image-14.jpeg\",\n type: \"image/jpeg\",\n id: \"12345678\"\n });\n\n expect(fileKey.toString()).toEqual(\"12345678/image-14.jpeg\");\n });\n\n it(\"should generate a file key containing prefix\", () => {\n const fileKey = new FileKey({\n size: 1071690,\n name: \"image-14.jpeg\",\n type: \"image/jpeg\",\n keyPrefix: \"prefix\"\n });\n\n expect(fileKey.toString()).toEqual(\"prefix/image-14.jpeg\");\n });\n\n it(\"should generate a file key containing id and prefix\", () => {\n const fileKey = new FileKey({\n size: 1071690,\n name: \"image-14.jpeg\",\n type: \"image/jpeg\",\n id: \"12345678\",\n keyPrefix: \"prefix\"\n });\n\n expect(fileKey.toString()).toEqual(\"prefix/12345678/image-14.jpeg\");\n });\n\n it(\"should use the key defined in the input\", () => {\n const fileKey = new FileKey({\n size: 1071690,\n name: \"image\",\n type: \"image/jpeg\",\n key: \"image-14.jpg\"\n });\n\n expect(fileKey.toString()).toEqual(\"image-14.jpg\");\n });\n});\n"],"mappings":"AAAA,SAASA,QAAQ,EAAEC,EAAE,EAAEC,MAAM,QAAQ,QAAQ;AAC7C,SAASC,OAAO;AAEhBH,QAAQ,CAAC,SAAS,EAAE,MAAM;EACtBC,EAAE,CAAC,gEAAgE,EAAE,MAAM;IACvE,MAAMG,OAAO,GAAG,IAAID,OAAO,CAAC;MACxBE,IAAI,EAAE,OAAO;MACbC,IAAI,EAAE,cAAc;MACpBC,IAAI,EAAE;IACV,CAAC,CAAC;IAEFL,MAAM,CAACE,OAAO,CAACI,QAAQ,CAAC,CAAC,CAAC,CAACC,OAAO,CAAC,cAAc,CAAC;EACtD,CAAC,CAAC;EAEFR,EAAE,CAAC,+DAA+D,EAAE,MAAM;IACtE,MAAMG,OAAO,GAAG,IAAID,OAAO,CAAC;MACxBE,IAAI,EAAE,OAAO;MACbC,IAAI,EAAE,UAAU;MAChBC,IAAI,EAAE;IACV,CAAC,CAAC;IAEFL,MAAM,CAACE,OAAO,CAACI,QAAQ,CAAC,CAAC,CAAC,CAACC,OAAO,CAAC,cAAc,CAAC;EACtD,CAAC,CAAC;EAEFR,EAAE,CAAC,0CAA0C,EAAE,MAAM;IACjD,MAAMG,OAAO,GAAG,IAAID,OAAO,CAAC;MACxBE,IAAI,EAAE,OAAO;MACbC,IAAI,EAAE,eAAe;MACrBC,IAAI,EAAE,YAAY;MAClBG,EAAE,EAAE;IACR,CAAC,CAAC;IAEFR,MAAM,CAACE,OAAO,CAACI,QAAQ,CAAC,CAAC,CAAC,CAACC,OAAO,CAAC,wBAAwB,CAAC;EAChE,CAAC,CAAC;EAEFR,EAAE,CAAC,8CAA8C,EAAE,MAAM;IACrD,MAAMG,OAAO,GAAG,IAAID,OAAO,CAAC;MACxBE,IAAI,EAAE,OAAO;MACbC,IAAI,EAAE,eAAe;MACrBC,IAAI,EAAE,YAAY;MAClBI,SAAS,EAAE;IACf,CAAC,CAAC;IAEFT,MAAM,CAACE,OAAO,CAACI,QAAQ,CAAC,CAAC,CAAC,CAACC,OAAO,CAAC,sBAAsB,CAAC;EAC9D,CAAC,CAAC;EAEFR,EAAE,CAAC,qDAAqD,EAAE,MAAM;IAC5D,MAAMG,OAAO,GAAG,IAAID,OAAO,CAAC;MACxBE,IAAI,EAAE,OAAO;MACbC,IAAI,EAAE,eAAe;MACrBC,IAAI,EAAE,YAAY;MAClBG,EAAE,EAAE,UAAU;MACdC,SAAS,EAAE;IACf,CAAC,CAAC;IAEFT,MAAM,CAACE,OAAO,CAACI,QAAQ,CAAC,CAAC,CAAC,CAACC,OAAO,CAAC,+BAA+B,CAAC;EACvE,CAAC,CAAC;EAEFR,EAAE,CAAC,yCAAyC,EAAE,MAAM;IAChD,MAAMG,OAAO,GAAG,IAAID,OAAO,CAAC;MACxBE,IAAI,EAAE,OAAO;MACbC,IAAI,EAAE,OAAO;MACbC,IAAI,EAAE,YAAY;MAClBK,GAAG,EAAE;IACT,CAAC,CAAC;IAEFV,MAAM,CAACE,OAAO,CAACI,QAAQ,CAAC,CAAC,CAAC,CAACC,OAAO,CAAC,cAAc,CAAC;EACtD,CAAC,CAAC;AACN,CAAC,CAAC","ignoreList":[]}
|
package/utils/FileNormalizer.js
CHANGED
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
import { mdbid } from "@webiny/utils";
|
|
2
2
|
import { FileKey } from "./FileKey.js";
|
|
3
|
+
import { mimeTypes } from "./mimeTypes.js";
|
|
4
|
+
const extensionToMime = new Map();
|
|
5
|
+
for (const [mime, extensions] of Object.entries(mimeTypes)) {
|
|
6
|
+
for (const ext of extensions) {
|
|
7
|
+
if (!extensionToMime.has(ext)) {
|
|
8
|
+
extensionToMime.set(ext, mime);
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
function resolveTypeFromName(name) {
|
|
13
|
+
const ext = name.slice(name.lastIndexOf(".") + 1).toLowerCase();
|
|
14
|
+
return extensionToMime.get(ext) || "application/octet-stream";
|
|
15
|
+
}
|
|
16
|
+
|
|
3
17
|
/**
|
|
4
18
|
* FileNormalizer normalizes file data, before it's signed for upload to S3.
|
|
5
19
|
* It generates a unique file id, and makes sure that the file key includes the unique id.
|
|
@@ -13,7 +27,7 @@ export class FileNormalizer {
|
|
|
13
27
|
const data = {
|
|
14
28
|
...payload,
|
|
15
29
|
id: payload.id || mdbid(),
|
|
16
|
-
type: payload.type ||
|
|
30
|
+
type: payload.type || resolveTypeFromName(payload.name)
|
|
17
31
|
};
|
|
18
32
|
const key = new FileKey(data);
|
|
19
33
|
const defaultKey = key.toString();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["mdbid","FileKey","FileNormalizer","constructor","modifier","normalizeFile","payload","data","id","type","key","defaultKey","toString","file","
|
|
1
|
+
{"version":3,"names":["mdbid","FileKey","mimeTypes","extensionToMime","Map","mime","extensions","Object","entries","ext","has","set","resolveTypeFromName","name","slice","lastIndexOf","toLowerCase","get","FileNormalizer","constructor","modifier","normalizeFile","payload","data","id","type","key","defaultKey","toString","file","size","assign","setKey"],"sources":["FileNormalizer.ts"],"sourcesContent":["import { mdbid } from \"@webiny/utils\";\nimport type { FileData, PresignedPostPayloadData } from \"~/types.js\";\nimport { FileKey } from \"~/utils/FileKey.js\";\nimport { mimeTypes } from \"~/utils/mimeTypes.js\";\nimport type { FileModifier } from \"./FileUploadModifier.js\";\n\nexport interface FileToSign {\n name: string;\n key: string;\n type: string;\n size: number;\n}\n\nconst extensionToMime = new Map<string, string>();\nfor (const [mime, extensions] of Object.entries(mimeTypes)) {\n for (const ext of extensions) {\n if (!extensionToMime.has(ext)) {\n extensionToMime.set(ext, mime);\n }\n }\n}\n\nfunction resolveTypeFromName(name: string): string {\n const ext = name.slice(name.lastIndexOf(\".\") + 1).toLowerCase();\n return extensionToMime.get(ext) || \"application/octet-stream\";\n}\n\n/**\n * FileNormalizer normalizes file data, before it's signed for upload to S3.\n * It generates a unique file id, and makes sure that the file key includes the unique id.\n *\n */\nexport class FileNormalizer {\n private readonly modifier: FileModifier | undefined;\n\n constructor(modifier?: FileModifier) {\n this.modifier = modifier;\n }\n\n async normalizeFile(payload: PresignedPostPayloadData): Promise<FileData> {\n const data = {\n ...payload,\n id: payload.id || mdbid(),\n type: payload.type || resolveTypeFromName(payload.name)\n };\n\n const key = new FileKey(data);\n const defaultKey = key.toString();\n\n const file: FileToSign = {\n name: data.name,\n type: data.type,\n key: defaultKey,\n size: data.size\n };\n\n if (this.modifier) {\n Object.assign(file, await this.modifier(file));\n }\n\n if (defaultKey !== file.key) {\n key.setKey(file.key);\n }\n\n return {\n id: data.id,\n key: key.toString(),\n name: file.name,\n size: file.size,\n type: file.type\n };\n }\n}\n"],"mappings":"AAAA,SAASA,KAAK,QAAQ,eAAe;AAErC,SAASC,OAAO;AAChB,SAASC,SAAS;AAUlB,MAAMC,eAAe,GAAG,IAAIC,GAAG,CAAiB,CAAC;AACjD,KAAK,MAAM,CAACC,IAAI,EAAEC,UAAU,CAAC,IAAIC,MAAM,CAACC,OAAO,CAACN,SAAS,CAAC,EAAE;EACxD,KAAK,MAAMO,GAAG,IAAIH,UAAU,EAAE;IAC1B,IAAI,CAACH,eAAe,CAACO,GAAG,CAACD,GAAG,CAAC,EAAE;MAC3BN,eAAe,CAACQ,GAAG,CAACF,GAAG,EAAEJ,IAAI,CAAC;IAClC;EACJ;AACJ;AAEA,SAASO,mBAAmBA,CAACC,IAAY,EAAU;EAC/C,MAAMJ,GAAG,GAAGI,IAAI,CAACC,KAAK,CAACD,IAAI,CAACE,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAACC,WAAW,CAAC,CAAC;EAC/D,OAAOb,eAAe,CAACc,GAAG,CAACR,GAAG,CAAC,IAAI,0BAA0B;AACjE;;AAEA;AACA;AACA;AACA;AACA;AACA,OAAO,MAAMS,cAAc,CAAC;EAGxBC,WAAWA,CAACC,QAAuB,EAAE;IACjC,IAAI,CAACA,QAAQ,GAAGA,QAAQ;EAC5B;EAEA,MAAMC,aAAaA,CAACC,OAAiC,EAAqB;IACtE,MAAMC,IAAI,GAAG;MACT,GAAGD,OAAO;MACVE,EAAE,EAAEF,OAAO,CAACE,EAAE,IAAIxB,KAAK,CAAC,CAAC;MACzByB,IAAI,EAAEH,OAAO,CAACG,IAAI,IAAIb,mBAAmB,CAACU,OAAO,CAACT,IAAI;IAC1D,CAAC;IAED,MAAMa,GAAG,GAAG,IAAIzB,OAAO,CAACsB,IAAI,CAAC;IAC7B,MAAMI,UAAU,GAAGD,GAAG,CAACE,QAAQ,CAAC,CAAC;IAEjC,MAAMC,IAAgB,GAAG;MACrBhB,IAAI,EAAEU,IAAI,CAACV,IAAI;MACfY,IAAI,EAAEF,IAAI,CAACE,IAAI;MACfC,GAAG,EAAEC,UAAU;MACfG,IAAI,EAAEP,IAAI,CAACO;IACf,CAAC;IAED,IAAI,IAAI,CAACV,QAAQ,EAAE;MACfb,MAAM,CAACwB,MAAM,CAACF,IAAI,EAAE,MAAM,IAAI,CAACT,QAAQ,CAACS,IAAI,CAAC,CAAC;IAClD;IAEA,IAAIF,UAAU,KAAKE,IAAI,CAACH,GAAG,EAAE;MACzBA,GAAG,CAACM,MAAM,CAACH,IAAI,CAACH,GAAG,CAAC;IACxB;IAEA,OAAO;MACHF,EAAE,EAAED,IAAI,CAACC,EAAE;MACXE,GAAG,EAAEA,GAAG,CAACE,QAAQ,CAAC,CAAC;MACnBf,IAAI,EAAEgB,IAAI,CAAChB,IAAI;MACfiB,IAAI,EAAED,IAAI,CAACC,IAAI;MACfL,IAAI,EAAEI,IAAI,CAACJ;IACf,CAAC;EACL;AACJ","ignoreList":[]}
|
package/utils/mimeTypes.js
CHANGED
package/utils/mimeTypes.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["vendorTypes","standardTypes","mimeTypes"],"sources":["mimeTypes.ts"],"sourcesContent":["
|
|
1
|
+
{"version":3,"names":["vendorTypes","standardTypes","mimeTypes"],"sources":["mimeTypes.ts"],"sourcesContent":["import vendorTypes from \"mime/types/other.js\";\nimport standardTypes from \"mime/types/standard.js\";\n\n/**\n * We need to get all extensions that are defined for a specific content type.\n * This operation is not available via the `mime` package, so we create such an object ourselves.\n */\nexport const mimeTypes: Record<string, string[]> = {\n ...vendorTypes,\n ...standardTypes\n};\n"],"mappings":"AAAA,OAAOA,WAAW,MAAM,qBAAqB;AAC7C,OAAOC,aAAa,MAAM,wBAAwB;;AAElD;AACA;AACA;AACA;AACA,OAAO,MAAMC,SAAmC,GAAG;EAC/C,GAAGF,WAAW;EACd,GAAGC;AACP,CAAC","ignoreList":[]}
|