@webiny/api-file-manager-s3 6.4.11 → 6.6.0-alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/FileManagerS3Feature.d.ts +9 -0
- package/FileManagerS3Feature.js +27 -0
- package/FileManagerS3Feature.js.map +1 -0
- package/assetDelivery/abstractions.d.ts +2 -0
- package/assetDelivery/abstractions.js.map +1 -1
- package/assetDelivery/assetDeliveryConfig.d.ts +1 -1
- package/assetDelivery/assetDeliveryConfig.js +0 -2
- package/assetDelivery/assetDeliveryConfig.js.map +1 -1
- package/assetDelivery/feature.js +3 -2
- package/assetDelivery/feature.js.map +1 -1
- package/assetDelivery/s3/LazySharpTransform.d.ts +34 -0
- package/assetDelivery/s3/LazySharpTransform.js +34 -0
- package/assetDelivery/s3/LazySharpTransform.js.map +1 -0
- package/assetDelivery/s3/SharpTransform.d.ts +15 -7
- package/assetDelivery/s3/SharpTransform.js +112 -101
- package/assetDelivery/s3/SharpTransform.js.map +1 -1
- package/assetDelivery/threatDetection/createThreatDetectionEventHandler.d.ts +21 -1
- package/assetDelivery/threatDetection/createThreatDetectionEventHandler.js +43 -27
- package/assetDelivery/threatDetection/createThreatDetectionEventHandler.js.map +1 -1
- package/assetDelivery/threatDetection/processThreatScanResult.js +9 -7
- package/assetDelivery/threatDetection/processThreatScanResult.js.map +1 -1
- package/assetDelivery/types.d.ts +3 -0
- package/enterprise/ApplyThreatScanning/CreateFileWithThreatScanDecorator.d.ts +3 -1
- package/enterprise/ApplyThreatScanning/CreateFileWithThreatScanDecorator.js +7 -2
- package/enterprise/ApplyThreatScanning/CreateFileWithThreatScanDecorator.js.map +1 -1
- package/features/DeleteFileFromBucket/DeleteS3FolderTask.d.ts +1 -1
- package/features/ExtractMetadata/ExtractMetadataTask.d.ts +1 -1
- package/features/FlushCache/FlushCacheOnFileDeleteHandler.js +1 -1
- package/features/FlushCache/FlushCacheOnFileDeleteHandler.js.map +1 -1
- package/features/FlushCache/FlushCacheOnFileUpdateHandler.js +1 -1
- package/features/FlushCache/FlushCacheOnFileUpdateHandler.js.map +1 -1
- package/features/FlushCache/InvalidateCacheTask.d.ts +2 -2
- package/features/FlushCache/InvalidateCacheTask.js +2 -2
- package/features/FlushCache/InvalidateCacheTask.js.map +1 -1
- package/features/WriteFileMetadata/MetadataWriter.js +3 -1
- package/features/WriteFileMetadata/MetadataWriter.js.map +1 -1
- package/graphql/S3GraphQLSchema.d.ts +9 -0
- package/graphql/S3GraphQLSchema.js +229 -0
- package/graphql/S3GraphQLSchema.js.map +1 -0
- package/index.d.ts +2 -2
- package/index.js +1 -29
- package/package.json +21 -19
- package/utils/FileUploadModifier.d.ts +8 -2
- package/utils/FileUploadModifier.js +5 -3
- package/utils/FileUploadModifier.js.map +1 -1
- package/utils/createFileNormalizerFromContext.js +2 -2
- package/utils/createFileNormalizerFromContext.js.map +1 -1
- package/utils/uploadFileToS3.d.ts +1 -1
- package/graphql/schema.d.ts +0 -1
- package/graphql/schema.js +0 -203
- package/graphql/schema.js.map +0 -1
- package/index.js.map +0 -1
|
@@ -1,37 +1,53 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { EventBridgeEventHandler } from "@webiny/event-handler-aws/abstractions/handlers/EventBridgeEventHandler.js";
|
|
2
|
+
import { RequestContainer } from "@webiny/event-handler-core";
|
|
3
|
+
import { TenantContext } from "@webiny/api-core/features/tenancy/TenantContext/index.js";
|
|
4
|
+
import { GetTenantByIdUseCase } from "@webiny/api-core/features/tenancy/GetTenantById/index.js";
|
|
5
|
+
import { FeatureFlags } from "@webiny/api-core/features/featureFlags/abstractions.js";
|
|
3
6
|
import { GlobalKeyValueStore } from "@webiny/api-core/features/keyValueStore/index.js";
|
|
4
7
|
import { processThreatScanResult } from "./processThreatScanResult.js";
|
|
5
8
|
import { ObjectKey } from "./ObjectKey.js";
|
|
6
|
-
const
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
9
|
+
const DETAIL_TYPE = "GuardDuty Malware Protection Object Scan Result";
|
|
10
|
+
class ThreatDetectionEventBridgeLambdaHandlerImpl {
|
|
11
|
+
constructor(container, tenantCtx, getTenantById){
|
|
12
|
+
this.container = container;
|
|
13
|
+
this.tenantCtx = tenantCtx;
|
|
14
|
+
this.getTenantById = getTenantById;
|
|
15
|
+
}
|
|
16
|
+
async execute(eventCtx, _next) {
|
|
17
|
+
const payload = eventCtx.event;
|
|
18
|
+
if (payload["detail-type"] !== DETAIL_TYPE) return {
|
|
19
|
+
success: true
|
|
20
|
+
};
|
|
21
|
+
if (!this.container.resolve(FeatureFlags).get().isEnabled("fileManager.threatDetection")) return {
|
|
22
|
+
success: true
|
|
23
|
+
};
|
|
11
24
|
const objectKey = payload.detail.s3ObjectDetails.objectKey;
|
|
12
|
-
const keyValueStore =
|
|
25
|
+
const keyValueStore = this.container.resolve(GlobalKeyValueStore);
|
|
13
26
|
try {
|
|
14
27
|
const fileId = ObjectKey.from(objectKey).id();
|
|
15
28
|
const result = await keyValueStore.get(`FileManager/File/${fileId}/Metadata`);
|
|
16
|
-
if (result.
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
};
|
|
29
|
+
if (result.isOk()) {
|
|
30
|
+
const tenantResult = await this.getTenantById.execute(result.value.tenant);
|
|
31
|
+
if (tenantResult.isOk()) this.tenantCtx.setTenant(tenantResult.value);
|
|
32
|
+
}
|
|
21
33
|
} catch {}
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
34
|
+
await processThreatScanResult({
|
|
35
|
+
container: this.container
|
|
36
|
+
}, payload.detail);
|
|
37
|
+
return {
|
|
38
|
+
success: true
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
const ThreatDetectionEventBridgeLambdaHandler = EventBridgeEventHandler.createImplementation({
|
|
43
|
+
implementation: ThreatDetectionEventBridgeLambdaHandlerImpl,
|
|
44
|
+
dependencies: [
|
|
45
|
+
RequestContainer,
|
|
46
|
+
TenantContext,
|
|
47
|
+
GetTenantByIdUseCase
|
|
48
|
+
]
|
|
49
|
+
});
|
|
50
|
+
const createThreatDetectionEventHandler = ()=>[];
|
|
51
|
+
export { ThreatDetectionEventBridgeLambdaHandler, createThreatDetectionEventHandler };
|
|
36
52
|
|
|
37
53
|
//# sourceMappingURL=createThreatDetectionEventHandler.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"assetDelivery/threatDetection/createThreatDetectionEventHandler.js","sources":["../../../src/assetDelivery/threatDetection/createThreatDetectionEventHandler.ts"],"sourcesContent":["import {
|
|
1
|
+
{"version":3,"file":"assetDelivery/threatDetection/createThreatDetectionEventHandler.js","sources":["../../../src/assetDelivery/threatDetection/createThreatDetectionEventHandler.ts"],"sourcesContent":["import type { Container } from \"@webiny/feature/api\";\nimport type { EventBridgeEvent } from \"@webiny/aws-sdk/types/index.js\";\nimport {\n EventBridgeEventHandler,\n type EventBridgeResult\n} from \"@webiny/event-handler-aws/abstractions/handlers/EventBridgeEventHandler.js\";\nimport { RequestContainer } from \"@webiny/event-handler-core\";\nimport { TenantContext } from \"@webiny/api-core/features/tenancy/TenantContext/index.js\";\nimport { GetTenantByIdUseCase } from \"@webiny/api-core/features/tenancy/GetTenantById/index.js\";\nimport type { ITenantContext } from \"@webiny/api-core/features/tenancy/TenantContext/abstractions.js\";\nimport type { IGetTenantByIdUseCase } from \"@webiny/api-core/features/tenancy/GetTenantById/abstractions.js\";\nimport type { EventContext, NextFunction } from \"@webiny/event-handler-core\";\nimport type { ApiCoreContext } from \"@webiny/api-core/types/core.js\";\nimport { FeatureFlags } from \"@webiny/api-core/features/featureFlags/abstractions.js\";\nimport { GlobalKeyValueStore } from \"@webiny/api-core/features/keyValueStore/index.js\";\nimport { processThreatScanResult } from \"./processThreatScanResult.js\";\nimport { ObjectKey } from \"./ObjectKey.js\";\nimport type { GuardDutyEvent } from \"./types.js\";\n\nconst DETAIL_TYPE = \"GuardDuty Malware Protection Object Scan Result\";\n\nclass ThreatDetectionEventBridgeLambdaHandlerImpl implements EventBridgeEventHandler.Interface {\n constructor(\n private container: Container,\n private tenantCtx: ITenantContext,\n private getTenantById: IGetTenantByIdUseCase\n ) {}\n\n async execute(\n eventCtx: EventContext<EventBridgeEvent<string, GuardDutyEvent>>,\n _next: NextFunction\n ): Promise<EventBridgeResult> {\n const payload = eventCtx.event;\n if (payload[\"detail-type\"] !== DETAIL_TYPE) {\n return { success: true };\n }\n\n if (!this.container.resolve(FeatureFlags).get().isEnabled(\"fileManager.threatDetection\")) {\n return { success: true };\n }\n\n const objectKey = payload.detail.s3ObjectDetails.objectKey;\n const keyValueStore = this.container.resolve(GlobalKeyValueStore);\n\n try {\n const fileId = ObjectKey.from(objectKey).id();\n const result = await keyValueStore.get<{ tenant: string }>(\n `FileManager/File/${fileId}/Metadata`\n );\n\n if (result.isOk()) {\n const tenantResult = await this.getTenantById.execute(result.value.tenant);\n if (tenantResult.isOk()) {\n this.tenantCtx.setTenant(tenantResult.value);\n }\n }\n } catch {\n // If metadata can't be loaded, ignore — likely a rendition file.\n }\n\n await processThreatScanResult(\n { container: this.container } as unknown as ApiCoreContext,\n payload.detail\n );\n return { success: true };\n }\n}\n\nexport const ThreatDetectionEventBridgeLambdaHandler = EventBridgeEventHandler.createImplementation(\n {\n implementation: ThreatDetectionEventBridgeLambdaHandlerImpl,\n dependencies: [RequestContainer, TenantContext, GetTenantByIdUseCase]\n }\n);\n\n/**\n * @deprecated Use ThreatDetectionEventBridgeLambdaHandler instead.\n */\nexport const createThreatDetectionEventHandler = () => {\n return [];\n};\n"],"names":["DETAIL_TYPE","ThreatDetectionEventBridgeLambdaHandlerImpl","container","tenantCtx","getTenantById","eventCtx","_next","payload","FeatureFlags","objectKey","keyValueStore","GlobalKeyValueStore","fileId","ObjectKey","result","tenantResult","processThreatScanResult","ThreatDetectionEventBridgeLambdaHandler","EventBridgeEventHandler","RequestContainer","TenantContext","GetTenantByIdUseCase","createThreatDetectionEventHandler"],"mappings":";;;;;;;;AAmBA,MAAMA,cAAc;AAEpB,MAAMC;IACF,YACYC,SAAoB,EACpBC,SAAyB,EACzBC,aAAoC,CAC9C;aAHUF,SAAS,GAATA;aACAC,SAAS,GAATA;aACAC,aAAa,GAAbA;IACT;IAEH,MAAM,QACFC,QAAgE,EAChEC,KAAmB,EACO;QAC1B,MAAMC,UAAUF,SAAS,KAAK;QAC9B,IAAIE,OAAO,CAAC,cAAc,KAAKP,aAC3B,OAAO;YAAE,SAAS;QAAK;QAG3B,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,CAACQ,cAAc,GAAG,GAAG,SAAS,CAAC,gCACtD,OAAO;YAAE,SAAS;QAAK;QAG3B,MAAMC,YAAYF,QAAQ,MAAM,CAAC,eAAe,CAAC,SAAS;QAC1D,MAAMG,gBAAgB,IAAI,CAAC,SAAS,CAAC,OAAO,CAACC;QAE7C,IAAI;YACA,MAAMC,SAASC,UAAU,IAAI,CAACJ,WAAW,EAAE;YAC3C,MAAMK,SAAS,MAAMJ,cAAc,GAAG,CAClC,CAAC,iBAAiB,EAAEE,OAAO,SAAS,CAAC;YAGzC,IAAIE,OAAO,IAAI,IAAI;gBACf,MAAMC,eAAe,MAAM,IAAI,CAAC,aAAa,CAAC,OAAO,CAACD,OAAO,KAAK,CAAC,MAAM;gBACzE,IAAIC,aAAa,IAAI,IACjB,IAAI,CAAC,SAAS,CAAC,SAAS,CAACA,aAAa,KAAK;YAEnD;QACJ,EAAE,OAAM,CAER;QAEA,MAAMC,wBACF;YAAE,WAAW,IAAI,CAAC,SAAS;QAAC,GAC5BT,QAAQ,MAAM;QAElB,OAAO;YAAE,SAAS;QAAK;IAC3B;AACJ;AAEO,MAAMU,0CAA0CC,wBAAwB,oBAAoB,CAC/F;IACI,gBAAgBjB;IAChB,cAAc;QAACkB;QAAkBC;QAAeC;KAAqB;AACzE;AAMG,MAAMC,oCAAoC,IACtC,EAAE"}
|
|
@@ -1,14 +1,16 @@
|
|
|
1
1
|
import { UpdateFileUseCase } from "@webiny/api-file-manager/features/file/UpdateFile/index.js";
|
|
2
2
|
import { DeleteFileUseCase } from "@webiny/api-file-manager/features/file/DeleteFile/index.js";
|
|
3
|
-
import {
|
|
3
|
+
import { WebsocketsListConnectionsUseCase, WebsocketsSendToConnectionsUseCase } from "@webiny/api-websockets/exports/api.js";
|
|
4
4
|
import { ObjectKey } from "./ObjectKey.js";
|
|
5
5
|
import { GetFileUseCase } from "@webiny/api-file-manager/features/file/GetFile/index.js";
|
|
6
|
+
import { IdentityContext } from "@webiny/api-core/features/security/IdentityContext/abstractions.js";
|
|
6
7
|
const processThreatScanResult = async (context, eventDetail)=>{
|
|
7
|
-
const
|
|
8
|
+
const listConnections = context.container.resolve(WebsocketsListConnectionsUseCase);
|
|
9
|
+
const sendToConnections = context.container.resolve(WebsocketsSendToConnectionsUseCase);
|
|
8
10
|
const getFile = context.container.resolve(GetFileUseCase);
|
|
9
11
|
const updateFile = context.container.resolve(UpdateFileUseCase);
|
|
10
12
|
const deleteFile = context.container.resolve(DeleteFileUseCase);
|
|
11
|
-
await context.
|
|
13
|
+
await context.container.resolve(IdentityContext).withoutAuthorization(async ()=>{
|
|
12
14
|
const scanStatus = eventDetail.scanResultDetails.scanResultStatus;
|
|
13
15
|
const s3Object = eventDetail.s3ObjectDetails;
|
|
14
16
|
const fileId = ObjectKey.from(s3Object.objectKey).id();
|
|
@@ -16,7 +18,7 @@ const processThreatScanResult = async (context, eventDetail)=>{
|
|
|
16
18
|
if (fileResult.isFail()) return;
|
|
17
19
|
const file = fileResult.value;
|
|
18
20
|
let allConnections = [];
|
|
19
|
-
const connectionsResult = await
|
|
21
|
+
const connectionsResult = await listConnections.execute();
|
|
20
22
|
if (connectionsResult.isOk()) allConnections = connectionsResult.value;
|
|
21
23
|
if ("NO_THREATS_FOUND" === scanStatus) {
|
|
22
24
|
const newTags = file.tags.filter((tag)=>"threatScanInProgress" !== tag);
|
|
@@ -24,7 +26,7 @@ const processThreatScanResult = async (context, eventDetail)=>{
|
|
|
24
26
|
id: file.id,
|
|
25
27
|
tags: newTags
|
|
26
28
|
});
|
|
27
|
-
await
|
|
29
|
+
await sendToConnections.execute(allConnections, {
|
|
28
30
|
action: "fm.threatScan.noThreatFound",
|
|
29
31
|
data: {
|
|
30
32
|
id: file.id,
|
|
@@ -35,7 +37,7 @@ const processThreatScanResult = async (context, eventDetail)=>{
|
|
|
35
37
|
}
|
|
36
38
|
if ("THREATS_FOUND" === scanStatus) {
|
|
37
39
|
await deleteFile.execute(file.id);
|
|
38
|
-
await
|
|
40
|
+
await sendToConnections.execute(allConnections, {
|
|
39
41
|
action: "fm.threatScan.threatDetected",
|
|
40
42
|
data: {
|
|
41
43
|
id: file.id,
|
|
@@ -45,7 +47,7 @@ const processThreatScanResult = async (context, eventDetail)=>{
|
|
|
45
47
|
return;
|
|
46
48
|
}
|
|
47
49
|
await deleteFile.execute(file.id);
|
|
48
|
-
await
|
|
50
|
+
await sendToConnections.execute(allConnections, {
|
|
49
51
|
action: "fm.threatScan.unsupported",
|
|
50
52
|
data: {
|
|
51
53
|
id: file.id,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"assetDelivery/threatDetection/processThreatScanResult.js","sources":["../../../src/assetDelivery/threatDetection/processThreatScanResult.ts"],"sourcesContent":["import type { ApiCoreContext } from \"@webiny/api-core/types/core.js\";\nimport { UpdateFileUseCase } from \"@webiny/api-file-manager/features/file/UpdateFile/index.js\";\nimport { DeleteFileUseCase } from \"@webiny/api-file-manager/features/file/DeleteFile/index.js\";\nimport {
|
|
1
|
+
{"version":3,"file":"assetDelivery/threatDetection/processThreatScanResult.js","sources":["../../../src/assetDelivery/threatDetection/processThreatScanResult.ts"],"sourcesContent":["import type { ApiCoreContext } from \"@webiny/api-core/types/core.js\";\nimport { UpdateFileUseCase } from \"@webiny/api-file-manager/features/file/UpdateFile/index.js\";\nimport { DeleteFileUseCase } from \"@webiny/api-file-manager/features/file/DeleteFile/index.js\";\nimport {\n WebsocketsListConnectionsUseCase,\n WebsocketsSendToConnectionsUseCase,\n ConnectionRegistry\n} from \"@webiny/api-websockets/exports/api.js\";\nimport type { GuardDutyEvent } from \"./types.js\";\nimport { ObjectKey } from \"./ObjectKey.js\";\nimport { GetFileUseCase } from \"@webiny/api-file-manager/features/file/GetFile/index.js\";\nimport { IdentityContext } from \"@webiny/api-core/features/security/IdentityContext/abstractions.js\";\n\nexport const processThreatScanResult = async (\n context: ApiCoreContext,\n eventDetail: GuardDutyEvent\n) => {\n const listConnections = context.container.resolve(WebsocketsListConnectionsUseCase);\n const sendToConnections = context.container.resolve(WebsocketsSendToConnectionsUseCase);\n const getFile = context.container.resolve(GetFileUseCase);\n const updateFile = context.container.resolve(UpdateFileUseCase);\n const deleteFile = context.container.resolve(DeleteFileUseCase);\n\n await context.container.resolve(IdentityContext).withoutAuthorization(async () => {\n const scanStatus = eventDetail.scanResultDetails.scanResultStatus;\n const s3Object = eventDetail.s3ObjectDetails;\n\n const fileId = ObjectKey.from(s3Object.objectKey).id();\n const fileResult = await getFile.execute(fileId);\n\n if (fileResult.isFail()) {\n return;\n }\n\n const file = fileResult.value;\n\n let allConnections: ConnectionRegistry.Data[] = [];\n const connectionsResult = await listConnections.execute();\n if (connectionsResult.isOk()) {\n allConnections = connectionsResult.value;\n }\n\n if (scanStatus === \"NO_THREATS_FOUND\") {\n const newTags = file.tags.filter(tag => tag !== \"threatScanInProgress\");\n await updateFile.execute({\n id: file.id,\n tags: newTags\n });\n\n await sendToConnections.execute(allConnections, {\n action: \"fm.threatScan.noThreatFound\",\n data: {\n id: file.id,\n tags: newTags\n }\n });\n\n return;\n }\n\n if (scanStatus === \"THREATS_FOUND\") {\n // Delete the infected file.\n await deleteFile.execute(file.id);\n\n await sendToConnections.execute(allConnections, {\n action: \"fm.threatScan.threatDetected\",\n data: {\n id: file.id,\n name: file.name\n }\n });\n\n return;\n }\n\n // For all other outcomes, we delete the file, until better logic is implemented.\n await deleteFile.execute(file.id);\n\n await sendToConnections.execute(allConnections, {\n action: \"fm.threatScan.unsupported\",\n data: {\n id: file.id,\n name: file.name\n }\n });\n });\n};\n"],"names":["processThreatScanResult","context","eventDetail","listConnections","WebsocketsListConnectionsUseCase","sendToConnections","WebsocketsSendToConnectionsUseCase","getFile","GetFileUseCase","updateFile","UpdateFileUseCase","deleteFile","DeleteFileUseCase","IdentityContext","scanStatus","s3Object","fileId","ObjectKey","fileResult","file","allConnections","connectionsResult","newTags","tag"],"mappings":";;;;;;AAaO,MAAMA,0BAA0B,OACnCC,SACAC;IAEA,MAAMC,kBAAkBF,QAAQ,SAAS,CAAC,OAAO,CAACG;IAClD,MAAMC,oBAAoBJ,QAAQ,SAAS,CAAC,OAAO,CAACK;IACpD,MAAMC,UAAUN,QAAQ,SAAS,CAAC,OAAO,CAACO;IAC1C,MAAMC,aAAaR,QAAQ,SAAS,CAAC,OAAO,CAACS;IAC7C,MAAMC,aAAaV,QAAQ,SAAS,CAAC,OAAO,CAACW;IAE7C,MAAMX,QAAQ,SAAS,CAAC,OAAO,CAACY,iBAAiB,oBAAoB,CAAC;QAClE,MAAMC,aAAaZ,YAAY,iBAAiB,CAAC,gBAAgB;QACjE,MAAMa,WAAWb,YAAY,eAAe;QAE5C,MAAMc,SAASC,UAAU,IAAI,CAACF,SAAS,SAAS,EAAE,EAAE;QACpD,MAAMG,aAAa,MAAMX,QAAQ,OAAO,CAACS;QAEzC,IAAIE,WAAW,MAAM,IACjB;QAGJ,MAAMC,OAAOD,WAAW,KAAK;QAE7B,IAAIE,iBAA4C,EAAE;QAClD,MAAMC,oBAAoB,MAAMlB,gBAAgB,OAAO;QACvD,IAAIkB,kBAAkB,IAAI,IACtBD,iBAAiBC,kBAAkB,KAAK;QAG5C,IAAIP,AAAe,uBAAfA,YAAmC;YACnC,MAAMQ,UAAUH,KAAK,IAAI,CAAC,MAAM,CAACI,CAAAA,MAAOA,AAAQ,2BAARA;YACxC,MAAMd,WAAW,OAAO,CAAC;gBACrB,IAAIU,KAAK,EAAE;gBACX,MAAMG;YACV;YAEA,MAAMjB,kBAAkB,OAAO,CAACe,gBAAgB;gBAC5C,QAAQ;gBACR,MAAM;oBACF,IAAID,KAAK,EAAE;oBACX,MAAMG;gBACV;YACJ;YAEA;QACJ;QAEA,IAAIR,AAAe,oBAAfA,YAAgC;YAEhC,MAAMH,WAAW,OAAO,CAACQ,KAAK,EAAE;YAEhC,MAAMd,kBAAkB,OAAO,CAACe,gBAAgB;gBAC5C,QAAQ;gBACR,MAAM;oBACF,IAAID,KAAK,EAAE;oBACX,MAAMA,KAAK,IAAI;gBACnB;YACJ;YAEA;QACJ;QAGA,MAAMR,WAAW,OAAO,CAACQ,KAAK,EAAE;QAEhC,MAAMd,kBAAkB,OAAO,CAACe,gBAAgB;YAC5C,QAAQ;YACR,MAAM;gBACF,IAAID,KAAK,EAAE;gBACX,MAAMA,KAAK,IAAI;YACnB;QACJ;IACJ;AACJ"}
|
package/assetDelivery/types.d.ts
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
|
+
import type { ImageFormat } from "@webiny/api-file-manager/features/assetDelivery/transformation/index.js";
|
|
1
2
|
export type AssetDeliveryParams = {
|
|
2
3
|
imageResizeWidths?: number[];
|
|
4
|
+
/** Per-format encoder quality (1-100). Merged over the built-in defaults. */
|
|
5
|
+
imageQuality?: Partial<Record<ImageFormat, number>>;
|
|
3
6
|
/**
|
|
4
7
|
* BE CAREFUL!
|
|
5
8
|
* Setting this to more than 1 hour may cause your URLs to still expire before the desired expiration time.
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import { CreateFileUseCase } from "@webiny/api-file-manager/features/file/CreateFile/abstractions.js";
|
|
2
2
|
import type { CreateFileInput } from "@webiny/api-file-manager/features/file/CreateFile/abstractions.js";
|
|
3
|
+
import { FeatureFlags } from "@webiny/api-core/features/featureFlags/abstractions.js";
|
|
3
4
|
declare class CreateFileWithThreatScanDecoratorImpl implements CreateFileUseCase.Interface {
|
|
5
|
+
private featureFlags;
|
|
4
6
|
private decoratee;
|
|
5
|
-
constructor(decoratee: CreateFileUseCase.Interface);
|
|
7
|
+
constructor(featureFlags: FeatureFlags.Interface, decoratee: CreateFileUseCase.Interface);
|
|
6
8
|
execute(input: CreateFileInput, meta?: Record<string, any>): ReturnType<CreateFileUseCase.Interface["execute"]>;
|
|
7
9
|
}
|
|
8
10
|
export declare const CreateFileWithThreatScanDecorator: typeof CreateFileWithThreatScanDecoratorImpl & {
|
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
import { CreateFileUseCase } from "@webiny/api-file-manager/features/file/CreateFile/abstractions.js";
|
|
2
|
+
import { FeatureFlags } from "@webiny/api-core/features/featureFlags/abstractions.js";
|
|
2
3
|
class CreateFileWithThreatScanDecoratorImpl {
|
|
3
|
-
constructor(decoratee){
|
|
4
|
+
constructor(featureFlags, decoratee){
|
|
5
|
+
this.featureFlags = featureFlags;
|
|
4
6
|
this.decoratee = decoratee;
|
|
5
7
|
}
|
|
6
8
|
async execute(input, meta) {
|
|
9
|
+
if (!this.featureFlags.get().isEnabled("fileManager.threatDetection")) return this.decoratee.execute(input, meta);
|
|
7
10
|
const modifiedInput = {
|
|
8
11
|
...input,
|
|
9
12
|
tags: [
|
|
@@ -16,7 +19,9 @@ class CreateFileWithThreatScanDecoratorImpl {
|
|
|
16
19
|
}
|
|
17
20
|
const CreateFileWithThreatScanDecorator = CreateFileUseCase.createDecorator({
|
|
18
21
|
decorator: CreateFileWithThreatScanDecoratorImpl,
|
|
19
|
-
dependencies: [
|
|
22
|
+
dependencies: [
|
|
23
|
+
FeatureFlags
|
|
24
|
+
]
|
|
20
25
|
});
|
|
21
26
|
export { CreateFileWithThreatScanDecorator };
|
|
22
27
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"enterprise/ApplyThreatScanning/CreateFileWithThreatScanDecorator.js","sources":["../../../src/enterprise/ApplyThreatScanning/CreateFileWithThreatScanDecorator.ts"],"sourcesContent":["import { CreateFileUseCase } from \"@webiny/api-file-manager/features/file/CreateFile/abstractions.js\";\nimport type { CreateFileInput } from \"@webiny/api-file-manager/features/file/CreateFile/abstractions.js\";\n\nclass CreateFileWithThreatScanDecoratorImpl implements CreateFileUseCase.Interface {\n constructor(private decoratee: CreateFileUseCase.Interface) {}\n\n async execute(\n input: CreateFileInput,\n meta?: Record<string, any>\n ): ReturnType<CreateFileUseCase.Interface[\"execute\"]> {\n const modifiedInput: CreateFileInput = {\n ...input,\n tags: [...(input.tags || []), \"threatScanInProgress\"]\n };\n\n return this.decoratee.execute(modifiedInput, meta);\n }\n}\n\nexport const CreateFileWithThreatScanDecorator = CreateFileUseCase.createDecorator({\n decorator: CreateFileWithThreatScanDecoratorImpl,\n dependencies: []\n});\n"],"names":["CreateFileWithThreatScanDecoratorImpl","decoratee","input","meta","modifiedInput","CreateFileWithThreatScanDecorator","CreateFileUseCase"],"mappings":"
|
|
1
|
+
{"version":3,"file":"enterprise/ApplyThreatScanning/CreateFileWithThreatScanDecorator.js","sources":["../../../src/enterprise/ApplyThreatScanning/CreateFileWithThreatScanDecorator.ts"],"sourcesContent":["import { CreateFileUseCase } from \"@webiny/api-file-manager/features/file/CreateFile/abstractions.js\";\nimport type { CreateFileInput } from \"@webiny/api-file-manager/features/file/CreateFile/abstractions.js\";\nimport { FeatureFlags } from \"@webiny/api-core/features/featureFlags/abstractions.js\";\n\nclass CreateFileWithThreatScanDecoratorImpl implements CreateFileUseCase.Interface {\n constructor(\n private featureFlags: FeatureFlags.Interface,\n private decoratee: CreateFileUseCase.Interface\n ) {}\n\n async execute(\n input: CreateFileInput,\n meta?: Record<string, any>\n ): ReturnType<CreateFileUseCase.Interface[\"execute\"]> {\n if (!this.featureFlags.get().isEnabled(\"fileManager.threatDetection\")) {\n return this.decoratee.execute(input, meta);\n }\n\n const modifiedInput: CreateFileInput = {\n ...input,\n tags: [...(input.tags || []), \"threatScanInProgress\"]\n };\n\n return this.decoratee.execute(modifiedInput, meta);\n }\n}\n\nexport const CreateFileWithThreatScanDecorator = CreateFileUseCase.createDecorator({\n decorator: CreateFileWithThreatScanDecoratorImpl,\n dependencies: [FeatureFlags]\n});\n"],"names":["CreateFileWithThreatScanDecoratorImpl","featureFlags","decoratee","input","meta","modifiedInput","CreateFileWithThreatScanDecorator","CreateFileUseCase","FeatureFlags"],"mappings":";;AAIA,MAAMA;IACF,YACYC,YAAoC,EACpCC,SAAsC,CAChD;aAFUD,YAAY,GAAZA;aACAC,SAAS,GAATA;IACT;IAEH,MAAM,QACFC,KAAsB,EACtBC,IAA0B,EACwB;QAClD,IAAI,CAAC,IAAI,CAAC,YAAY,CAAC,GAAG,GAAG,SAAS,CAAC,gCACnC,OAAO,IAAI,CAAC,SAAS,CAAC,OAAO,CAACD,OAAOC;QAGzC,MAAMC,gBAAiC;YACnC,GAAGF,KAAK;YACR,MAAM;mBAAKA,MAAM,IAAI,IAAI,EAAE;gBAAG;aAAuB;QACzD;QAEA,OAAO,IAAI,CAAC,SAAS,CAAC,OAAO,CAACE,eAAeD;IACjD;AACJ;AAEO,MAAME,oCAAoCC,kBAAkB,eAAe,CAAC;IAC/E,WAAWP;IACX,cAAc;QAACQ;KAAa;AAChC"}
|
|
@@ -23,7 +23,7 @@ declare class DeleteS3FolderTask implements TaskDefinition.Interface<DeleteS3Fol
|
|
|
23
23
|
description: string;
|
|
24
24
|
maxIterations: number;
|
|
25
25
|
isPrivate: boolean;
|
|
26
|
-
readonly selfCleanup: ("
|
|
26
|
+
readonly selfCleanup: ("onAbort" | "onSuccess")[];
|
|
27
27
|
run({ input, controller }: TaskDefinition.RunParams<DeleteS3FolderInput>): Promise<TaskDefinition.Result<DeleteS3FolderInput>>;
|
|
28
28
|
}
|
|
29
29
|
export declare const DeleteS3FolderTaskDefinition: typeof DeleteS3FolderTask & {
|
|
@@ -13,7 +13,7 @@ declare class ExtractMetadataTask implements TaskDefinition.Interface<ExtractMet
|
|
|
13
13
|
maxIterations: number;
|
|
14
14
|
isPrivate: boolean;
|
|
15
15
|
databaseLogs: boolean;
|
|
16
|
-
selfCleanup: ("
|
|
16
|
+
selfCleanup: ("onAbort" | "onSuccess")[];
|
|
17
17
|
constructor(keyValueStore: GlobalKeyValueStore.Interface, updateFileUseCase: UpdateFileUseCase.Interface);
|
|
18
18
|
run({ input, controller }: TaskDefinition.RunParams<ExtractMetadataInput>): Promise<TaskDefinition.Result<ExtractMetadataInput>>;
|
|
19
19
|
private cleanValues;
|
|
@@ -9,7 +9,7 @@ class FlushCacheOnFileDeleteHandlerImpl {
|
|
|
9
9
|
async handle(event) {
|
|
10
10
|
const { file } = event.payload;
|
|
11
11
|
await this.taskService.trigger({
|
|
12
|
-
definition: "
|
|
12
|
+
definition: "invalidateAssetCache",
|
|
13
13
|
input: {
|
|
14
14
|
caller: "fm-before-delete",
|
|
15
15
|
paths: this.pathsGenerator.generate(file.id)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"features/FlushCache/FlushCacheOnFileDeleteHandler.js","sources":["../../../src/features/FlushCache/FlushCacheOnFileDeleteHandler.ts"],"sourcesContent":["import { FileAfterDeleteEventHandler } from \"@webiny/api-file-manager/features/file/DeleteFile/events.js\";\nimport { TaskService } from \"@webiny/api-core/features/task/TaskService/index.js\";\nimport { CdnPathsGenerator } from \"~/utils/CdnPathsGenerator.js\";\n\nclass FlushCacheOnFileDeleteHandlerImpl implements FileAfterDeleteEventHandler.Interface {\n private readonly pathsGenerator: CdnPathsGenerator;\n\n constructor(private taskService: TaskService.Interface) {\n this.pathsGenerator = new CdnPathsGenerator();\n }\n\n async handle(event: FileAfterDeleteEventHandler.Event): Promise<void> {\n const { file } = event.payload;\n\n await this.taskService.trigger({\n definition: \"
|
|
1
|
+
{"version":3,"file":"features/FlushCache/FlushCacheOnFileDeleteHandler.js","sources":["../../../src/features/FlushCache/FlushCacheOnFileDeleteHandler.ts"],"sourcesContent":["import { FileAfterDeleteEventHandler } from \"@webiny/api-file-manager/features/file/DeleteFile/events.js\";\nimport { TaskService } from \"@webiny/api-core/features/task/TaskService/index.js\";\nimport { CdnPathsGenerator } from \"~/utils/CdnPathsGenerator.js\";\n\nclass FlushCacheOnFileDeleteHandlerImpl implements FileAfterDeleteEventHandler.Interface {\n private readonly pathsGenerator: CdnPathsGenerator;\n\n constructor(private taskService: TaskService.Interface) {\n this.pathsGenerator = new CdnPathsGenerator();\n }\n\n async handle(event: FileAfterDeleteEventHandler.Event): Promise<void> {\n const { file } = event.payload;\n\n await this.taskService.trigger({\n definition: \"invalidateAssetCache\",\n input: {\n caller: \"fm-before-delete\",\n paths: this.pathsGenerator.generate(file.id)\n }\n });\n }\n}\n\nexport const FlushCacheOnFileDeleteHandler = FileAfterDeleteEventHandler.createImplementation({\n implementation: FlushCacheOnFileDeleteHandlerImpl,\n dependencies: [TaskService]\n});\n"],"names":["FlushCacheOnFileDeleteHandlerImpl","taskService","CdnPathsGenerator","event","file","FlushCacheOnFileDeleteHandler","FileAfterDeleteEventHandler","TaskService"],"mappings":";;;AAIA,MAAMA;IAGF,YAAoBC,WAAkC,CAAE;aAApCA,WAAW,GAAXA;QAChB,IAAI,CAAC,cAAc,GAAG,IAAIC;IAC9B;IAEA,MAAM,OAAOC,KAAwC,EAAiB;QAClE,MAAM,EAAEC,IAAI,EAAE,GAAGD,MAAM,OAAO;QAE9B,MAAM,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC;YAC3B,YAAY;YACZ,OAAO;gBACH,QAAQ;gBACR,OAAO,IAAI,CAAC,cAAc,CAAC,QAAQ,CAACC,KAAK,EAAE;YAC/C;QACJ;IACJ;AACJ;AAEO,MAAMC,gCAAgCC,4BAA4B,oBAAoB,CAAC;IAC1F,gBAAgBN;IAChB,cAAc;QAACO;KAAY;AAC/B"}
|
|
@@ -12,7 +12,7 @@ class FlushCacheOnFileUpdateHandlerImpl {
|
|
|
12
12
|
const newAccessControl = file.accessControl;
|
|
13
13
|
if (prevAccessControl?.type === newAccessControl?.type) return;
|
|
14
14
|
await this.taskService.trigger({
|
|
15
|
-
definition: "
|
|
15
|
+
definition: "invalidateAssetCache",
|
|
16
16
|
input: {
|
|
17
17
|
caller: "fm-before-update",
|
|
18
18
|
paths: this.pathsGenerator.generate(file.id)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"features/FlushCache/FlushCacheOnFileUpdateHandler.js","sources":["../../../src/features/FlushCache/FlushCacheOnFileUpdateHandler.ts"],"sourcesContent":["import { FileBeforeUpdateEventHandler } from \"@webiny/api-file-manager/features/file/UpdateFile/events.js\";\nimport { TaskService } from \"@webiny/api-core/features/task/TaskService/index.js\";\nimport { CdnPathsGenerator } from \"~/utils/CdnPathsGenerator.js\";\n\nclass FlushCacheOnFileUpdateHandlerImpl implements FileBeforeUpdateEventHandler.Interface {\n private readonly pathsGenerator: CdnPathsGenerator;\n\n constructor(private taskService: TaskService.Interface) {\n this.pathsGenerator = new CdnPathsGenerator();\n }\n\n async handle(event: FileBeforeUpdateEventHandler.Event): Promise<void> {\n const { file, original } = event.payload;\n\n const prevAccessControl = original.accessControl;\n const newAccessControl = file.accessControl;\n\n // Only trigger cache flush if access control type has changed\n if (prevAccessControl?.type === newAccessControl?.type) {\n return;\n }\n\n await this.taskService.trigger({\n definition: \"
|
|
1
|
+
{"version":3,"file":"features/FlushCache/FlushCacheOnFileUpdateHandler.js","sources":["../../../src/features/FlushCache/FlushCacheOnFileUpdateHandler.ts"],"sourcesContent":["import { FileBeforeUpdateEventHandler } from \"@webiny/api-file-manager/features/file/UpdateFile/events.js\";\nimport { TaskService } from \"@webiny/api-core/features/task/TaskService/index.js\";\nimport { CdnPathsGenerator } from \"~/utils/CdnPathsGenerator.js\";\n\nclass FlushCacheOnFileUpdateHandlerImpl implements FileBeforeUpdateEventHandler.Interface {\n private readonly pathsGenerator: CdnPathsGenerator;\n\n constructor(private taskService: TaskService.Interface) {\n this.pathsGenerator = new CdnPathsGenerator();\n }\n\n async handle(event: FileBeforeUpdateEventHandler.Event): Promise<void> {\n const { file, original } = event.payload;\n\n const prevAccessControl = original.accessControl;\n const newAccessControl = file.accessControl;\n\n // Only trigger cache flush if access control type has changed\n if (prevAccessControl?.type === newAccessControl?.type) {\n return;\n }\n\n await this.taskService.trigger({\n definition: \"invalidateAssetCache\",\n input: {\n caller: \"fm-before-update\",\n paths: this.pathsGenerator.generate(file.id)\n }\n });\n }\n}\n\nexport const FlushCacheOnFileUpdateHandler = FileBeforeUpdateEventHandler.createImplementation({\n implementation: FlushCacheOnFileUpdateHandlerImpl,\n dependencies: [TaskService]\n});\n"],"names":["FlushCacheOnFileUpdateHandlerImpl","taskService","CdnPathsGenerator","event","file","original","prevAccessControl","newAccessControl","FlushCacheOnFileUpdateHandler","FileBeforeUpdateEventHandler","TaskService"],"mappings":";;;AAIA,MAAMA;IAGF,YAAoBC,WAAkC,CAAE;aAApCA,WAAW,GAAXA;QAChB,IAAI,CAAC,cAAc,GAAG,IAAIC;IAC9B;IAEA,MAAM,OAAOC,KAAyC,EAAiB;QACnE,MAAM,EAAEC,IAAI,EAAEC,QAAQ,EAAE,GAAGF,MAAM,OAAO;QAExC,MAAMG,oBAAoBD,SAAS,aAAa;QAChD,MAAME,mBAAmBH,KAAK,aAAa;QAG3C,IAAIE,mBAAmB,SAASC,kBAAkB,MAC9C;QAGJ,MAAM,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC;YAC3B,YAAY;YACZ,OAAO;gBACH,QAAQ;gBACR,OAAO,IAAI,CAAC,cAAc,CAAC,QAAQ,CAACH,KAAK,EAAE;YAC/C;QACJ;IACJ;AACJ;AAEO,MAAMI,gCAAgCC,6BAA6B,oBAAoB,CAAC;IAC3F,gBAAgBT;IAChB,cAAc;QAACU;KAAY;AAC/B"}
|
|
@@ -15,9 +15,9 @@ declare class InvalidateCloudfrontCacheTask implements TaskDefinition.Interface<
|
|
|
15
15
|
description: string;
|
|
16
16
|
maxIterations: number;
|
|
17
17
|
isPrivate: boolean;
|
|
18
|
-
selfCleanup: ("
|
|
18
|
+
selfCleanup: ("onAbort" | "onSuccess")[];
|
|
19
19
|
private continueIfCode;
|
|
20
|
-
run({ input, controller }: TaskDefinition.RunParams<InvalidateCacheInput>): Promise<import("@webiny/api-core/features/task/TaskDefinition/abstractions").
|
|
20
|
+
run({ input, controller }: TaskDefinition.RunParams<InvalidateCacheInput>): Promise<import("@webiny/api-core/features/task/TaskDefinition/abstractions").ITaskResultAborted | import("@webiny/api-core/features/task/TaskDefinition/abstractions").ITaskResultError | TaskDefinition.ResultContinue<InvalidateCacheInput> | TaskDefinition.ResultDone<import("@webiny/api-core/features/task/TaskDefinition/abstractions").ITaskOutput>>;
|
|
21
21
|
private invalidateCache;
|
|
22
22
|
}
|
|
23
23
|
export declare const InvalidateCloudfrontCacheTaskDefinition: typeof InvalidateCloudfrontCacheTask & {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ServiceDiscovery } from "@webiny/api";
|
|
1
|
+
import { ServiceDiscovery } from "@webiny/api-core/features/serviceDiscovery/index.js";
|
|
2
2
|
import { CloudFront } from "@webiny/aws-sdk/client-cloudfront/index.js";
|
|
3
3
|
import { TaskDefinition } from "@webiny/api-core/features/task/TaskDefinition/index.js";
|
|
4
4
|
import { executeWithRetry } from "@webiny/utils";
|
|
@@ -51,7 +51,7 @@ class InvalidateCloudfrontCacheTask {
|
|
|
51
51
|
});
|
|
52
52
|
}
|
|
53
53
|
constructor(){
|
|
54
|
-
this.id = "
|
|
54
|
+
this.id = "invalidateAssetCache";
|
|
55
55
|
this.title = "Invalidate CloudFront Cache";
|
|
56
56
|
this.description = "A task to invalidate Cloudfront cache by given paths.";
|
|
57
57
|
this.maxIterations = 100;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"features/FlushCache/InvalidateCacheTask.js","sources":["../../../src/features/FlushCache/InvalidateCacheTask.ts"],"sourcesContent":["import { ServiceDiscovery } from \"@webiny/api\";\nimport { CloudFront } from \"@webiny/aws-sdk/client-cloudfront/index.js\";\nimport { TaskDefinition } from \"@webiny/api-core/features/task/TaskDefinition/index.js\";\nimport { executeWithRetry } from \"@webiny/utils\";\n\nclass ReturnContinue extends Error {}\n\nexport interface InvalidateCacheInput {\n /**\n * Caller of the task (e.g., `fm-before-update`, `fm-after-delete`).\n */\n caller: string;\n /**\n * Cache paths to invalidate.\n */\n paths: string[];\n}\n\nclass InvalidateCloudfrontCacheTask implements TaskDefinition.Interface<InvalidateCacheInput> {\n id = \"
|
|
1
|
+
{"version":3,"file":"features/FlushCache/InvalidateCacheTask.js","sources":["../../../src/features/FlushCache/InvalidateCacheTask.ts"],"sourcesContent":["import { ServiceDiscovery } from \"@webiny/api-core/features/serviceDiscovery/index.js\";\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 = \"invalidateAssetCache\";\n title = \"Invalidate CloudFront Cache\";\n description = \"A task to invalidate Cloudfront cache by given paths.\";\n maxIterations = 100;\n isPrivate = true;\n\n selfCleanup = [\"onSuccess\" as const, \"onAbort\" as const];\n\n private continueIfCode = [\"TooManyInvalidationsInProgress\", \"Throttling\"];\n\n public async run({ input, controller }: TaskDefinition.RunParams<InvalidateCacheInput>) {\n if (controller.runtime.isAborted()) {\n return controller.response.aborted();\n }\n\n const manifest = await ServiceDiscovery.load();\n\n if (!manifest) {\n return controller.response.error({\n message: `Unable to invalidate cache due to a missing service manifest.`,\n code: \"MISSING_SERVICE_MANIFEST\",\n data: {\n manifest: \"api\"\n }\n });\n }\n\n const { distributionId } = manifest.api.cloudfront;\n\n const invalidateCache = () => {\n return this.invalidateCache(input.caller, distributionId as string, input.paths);\n };\n\n try {\n await executeWithRetry(invalidateCache, {\n minTimeout: 2000,\n // instead of forever: true\n retries: 10000,\n onFailedAttempt: ({ error }) => {\n if (this.continueIfCode.includes(error.name)) {\n throw new ReturnContinue();\n }\n\n if (error.message.includes(\"not authorized to perform\")) {\n throw error;\n }\n\n if (controller.runtime.isCloseToTimeout()) {\n throw new ReturnContinue();\n }\n }\n });\n } catch (error) {\n if (error instanceof ReturnContinue) {\n return controller.response.continue(input);\n }\n\n return controller.response.error({\n message: error.message,\n code: \"EXECUTE_WITH_RETRY_FAILED\",\n data: input.paths\n });\n }\n\n return controller.response.done();\n }\n\n private async invalidateCache(\n caller: string,\n distributionId: string,\n paths: string[]\n ): Promise<void> {\n const cloudfront = new CloudFront();\n await cloudfront.createInvalidation({\n DistributionId: distributionId,\n InvalidationBatch: {\n CallerReference: `${new Date().getTime()}-${caller}`,\n Paths: {\n Quantity: paths.length,\n Items: paths\n }\n }\n });\n }\n}\n\nexport const InvalidateCloudfrontCacheTaskDefinition = TaskDefinition.createImplementation({\n implementation: InvalidateCloudfrontCacheTask,\n dependencies: []\n});\n"],"names":["ReturnContinue","Error","InvalidateCloudfrontCacheTask","input","controller","manifest","ServiceDiscovery","distributionId","invalidateCache","executeWithRetry","error","caller","paths","cloudfront","CloudFront","Date","InvalidateCloudfrontCacheTaskDefinition","TaskDefinition"],"mappings":";;;;AAKA,MAAMA,uBAAuBC;AAAO;AAapC,MAAMC;IAWF,MAAa,IAAI,EAAEC,KAAK,EAAEC,UAAU,EAAkD,EAAE;QACpF,IAAIA,WAAW,OAAO,CAAC,SAAS,IAC5B,OAAOA,WAAW,QAAQ,CAAC,OAAO;QAGtC,MAAMC,WAAW,MAAMC,iBAAiB,IAAI;QAE5C,IAAI,CAACD,UACD,OAAOD,WAAW,QAAQ,CAAC,KAAK,CAAC;YAC7B,SAAS;YACT,MAAM;YACN,MAAM;gBACF,UAAU;YACd;QACJ;QAGJ,MAAM,EAAEG,cAAc,EAAE,GAAGF,SAAS,GAAG,CAAC,UAAU;QAElD,MAAMG,kBAAkB,IACb,IAAI,CAAC,eAAe,CAACL,MAAM,MAAM,EAAEI,gBAA0BJ,MAAM,KAAK;QAGnF,IAAI;YACA,MAAMM,iBAAiBD,iBAAiB;gBACpC,YAAY;gBAEZ,SAAS;gBACT,iBAAiB,CAAC,EAAEE,KAAK,EAAE;oBACvB,IAAI,IAAI,CAAC,cAAc,CAAC,QAAQ,CAACA,MAAM,IAAI,GACvC,MAAM,IAAIV;oBAGd,IAAIU,MAAM,OAAO,CAAC,QAAQ,CAAC,8BACvB,MAAMA;oBAGV,IAAIN,WAAW,OAAO,CAAC,gBAAgB,IACnC,MAAM,IAAIJ;gBAElB;YACJ;QACJ,EAAE,OAAOU,OAAO;YACZ,IAAIA,iBAAiBV,gBACjB,OAAOI,WAAW,QAAQ,CAAC,QAAQ,CAACD;YAGxC,OAAOC,WAAW,QAAQ,CAAC,KAAK,CAAC;gBAC7B,SAASM,MAAM,OAAO;gBACtB,MAAM;gBACN,MAAMP,MAAM,KAAK;YACrB;QACJ;QAEA,OAAOC,WAAW,QAAQ,CAAC,IAAI;IACnC;IAEA,MAAc,gBACVO,MAAc,EACdJ,cAAsB,EACtBK,KAAe,EACF;QACb,MAAMC,aAAa,IAAIC;QACvB,MAAMD,WAAW,kBAAkB,CAAC;YAChC,gBAAgBN;YAChB,mBAAmB;gBACf,iBAAiB,GAAG,IAAIQ,OAAO,OAAO,GAAG,CAAC,EAAEJ,QAAQ;gBACpD,OAAO;oBACH,UAAUC,MAAM,MAAM;oBACtB,OAAOA;gBACX;YACJ;QACJ;IACJ;;aAnFA,EAAE,GAAG;aACL,KAAK,GAAG;aACR,WAAW,GAAG;aACd,aAAa,GAAG;aAChB,SAAS,GAAG;aAEZ,WAAW,GAAG;YAAC;YAAsB;SAAmB;aAEhD,cAAc,GAAG;YAAC;YAAkC;SAAa;;AA4E7E;AAEO,MAAMI,0CAA0CC,eAAe,oBAAoB,CAAC;IACvF,gBAAgBf;IAChB,cAAc,EAAE;AACpB"}
|
|
@@ -6,7 +6,9 @@ class MetadataWriter {
|
|
|
6
6
|
async write(files) {
|
|
7
7
|
const writers = files.map(async (file)=>{
|
|
8
8
|
const metadata = this.getMetadata(file);
|
|
9
|
-
|
|
9
|
+
const key = `FileManager/File/${file.id}/Metadata`;
|
|
10
|
+
const result = await this.keyValueStore.set(key, metadata);
|
|
11
|
+
if (result.isFail()) console.error(`[FileManagerS3] Failed to write delivery metadata "${key}":`, result.error);
|
|
10
12
|
});
|
|
11
13
|
await Promise.all(writers);
|
|
12
14
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"features/WriteFileMetadata/MetadataWriter.js","sources":["../../../src/features/WriteFileMetadata/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
|
|
1
|
+
{"version":3,"file":"features/WriteFileMetadata/MetadataWriter.js","sources":["../../../src/features/WriteFileMetadata/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 const key = `FileManager/File/${file.id}/Metadata`;\n // Check the result: the KV store returns a failed Result (it does not throw), so an\n // ignored failure here would silently break asset delivery (missing metadata → 404).\n const result = await this.keyValueStore.set(key, metadata);\n if (result.isFail()) {\n console.error(\n `[FileManagerS3] Failed to write delivery metadata \"${key}\":`,\n result.error\n );\n }\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"],"names":["MetadataWriter","tenantContext","keyValueStore","files","writers","file","metadata","key","result","console","Promise","tenant"],"mappings":"AAIO,MAAMA;IACT,YACYC,aAAsC,EACtCC,aAA4C,CACtD;aAFUD,aAAa,GAAbA;aACAC,aAAa,GAAbA;IACT;IAEH,MAAM,MAAMC,KAAa,EAAE;QAIvB,MAAMC,UAAUD,MAAM,GAAG,CAAC,OAAME;YAC5B,MAAMC,WAAW,IAAI,CAAC,WAAW,CAACD;YAClC,MAAME,MAAM,CAAC,iBAAiB,EAAEF,KAAK,EAAE,CAAC,SAAS,CAAC;YAGlD,MAAMG,SAAS,MAAM,IAAI,CAAC,aAAa,CAAC,GAAG,CAACD,KAAKD;YACjD,IAAIE,OAAO,MAAM,IACbC,QAAQ,KAAK,CACT,CAAC,mDAAmD,EAAEF,IAAI,EAAE,CAAC,EAC7DC,OAAO,KAAK;QAGxB;QAEA,MAAME,QAAQ,GAAG,CAACN;IACtB;IAEQ,YAAYC,IAAU,EAAE;QAC5B,MAAMM,SAAS,IAAI,CAAC,aAAa,CAAC,SAAS;QAC3C,OAAO;YACH,IAAIN,KAAK,EAAE;YACX,WAAW,CAAC,QAAQ,EAAEM,OAAO,EAAE,CAAC,OAAO,EAAEN,KAAK,GAAG,EAAE;YACnD,QAAQM,OAAO,EAAE;YACjB,MAAMN,KAAK,IAAI;YACf,aAAaA,KAAK,IAAI;QAC1B;IACJ;AACJ"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { CoreGraphQLSchemaFactory } from "@webiny/api-graphql/graphql/abstractions.js";
|
|
2
|
+
import { GraphQLSchemaBuilder } from "@webiny/api-graphql/features/GraphQLSchemaBuilder/abstractions.js";
|
|
3
|
+
declare class S3GraphQLSchemaImpl implements CoreGraphQLSchemaFactory.Interface {
|
|
4
|
+
execute(builder: GraphQLSchemaBuilder.Interface): CoreGraphQLSchemaFactory.Return;
|
|
5
|
+
}
|
|
6
|
+
export declare const S3GraphQLSchema: typeof S3GraphQLSchemaImpl & {
|
|
7
|
+
__abstraction: import("@webiny/di").Abstraction<import("@webiny/api-graphql/graphql/abstractions.core.js").ICoreGraphQLSchemaFactory>;
|
|
8
|
+
};
|
|
9
|
+
export {};
|