@webiny/api-file-manager-server 0.0.0-unstable.b6d7105cee → 6.6.0-alpha.0
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/FileManagerServerFeature.d.ts +5 -0
- package/FileManagerServerFeature.js +41 -0
- package/FileManagerServerFeature.js.map +1 -0
- package/assetDelivery/LocalAssetResolver.d.ts +6 -4
- package/assetDelivery/LocalAssetResolver.js +9 -9
- package/assetDelivery/LocalAssetResolver.js.map +1 -1
- package/assetDelivery/LocalOutputStrategy.d.ts +3 -2
- package/assetDelivery/LocalOutputStrategy.js +4 -4
- package/assetDelivery/LocalOutputStrategy.js.map +1 -1
- package/assetDelivery/LocalSharpTransform.d.ts +8 -14
- package/assetDelivery/LocalSharpTransform.js +72 -98
- package/assetDelivery/LocalSharpTransform.js.map +1 -1
- package/assetDelivery/abstractions.d.ts +0 -3
- package/assetDelivery/abstractions.js +1 -2
- package/assetDelivery/abstractions.js.map +1 -1
- package/assetDelivery/assetDeliveryConfig.d.ts +1 -1
- package/assetDelivery/feature.js +7 -9
- package/assetDelivery/feature.js.map +1 -1
- package/assetDelivery/types.d.ts +0 -3
- package/features/CleanupStaleMultipartUploads/CleanupStaleMultipartUploadsTask.d.ts +3 -0
- package/features/CleanupStaleMultipartUploads/CleanupStaleMultipartUploadsTask.js +18 -14
- package/features/CleanupStaleMultipartUploads/CleanupStaleMultipartUploadsTask.js.map +1 -1
- package/features/CompleteMultiPartUpload/CompleteMultiPartUploadUseCase.d.ts +7 -5
- package/features/CompleteMultiPartUpload/CompleteMultiPartUploadUseCase.js +8 -5
- package/features/CompleteMultiPartUpload/CompleteMultiPartUploadUseCase.js.map +1 -1
- package/features/CompleteMultiPartUpload/feature.js +2 -2
- package/features/CompleteMultiPartUpload/feature.js.map +1 -1
- package/features/CreateMultiPartUpload/CreateMultiPartUploadUseCase.d.ts +7 -7
- package/features/CreateMultiPartUpload/CreateMultiPartUploadUseCase.js +9 -10
- package/features/CreateMultiPartUpload/CreateMultiPartUploadUseCase.js.map +1 -1
- package/features/CreateMultiPartUpload/feature.js +2 -2
- package/features/CreateMultiPartUpload/feature.js.map +1 -1
- package/features/DeleteFileFromDisk/DeleteFileFromDiskHandler.d.ts +3 -1
- package/features/DeleteFileFromDisk/DeleteFileFromDiskHandler.js +6 -3
- package/features/DeleteFileFromDisk/DeleteFileFromDiskHandler.js.map +1 -1
- package/features/ExtractMetadata/ExtractMetadataTask.d.ts +3 -1
- package/features/ExtractMetadata/ExtractMetadataTask.js +6 -3
- package/features/ExtractMetadata/ExtractMetadataTask.js.map +1 -1
- package/features/FileManagerServerConfig/FileManagerServerConfig.d.ts +12 -0
- package/features/FileManagerServerConfig/FileManagerServerConfig.js +28 -0
- package/features/FileManagerServerConfig/FileManagerServerConfig.js.map +1 -0
- package/features/FileManagerServerConfig/abstractions.d.ts +10 -0
- package/features/FileManagerServerConfig/abstractions.js +5 -0
- package/features/FileManagerServerConfig/abstractions.js.map +1 -0
- package/features/FileManagerServerConfig/feature.d.ts +4 -0
- package/features/FileManagerServerConfig/feature.js +11 -0
- package/features/FileManagerServerConfig/feature.js.map +1 -0
- package/features/GetFileContentsById/GetFileContentsByIdUseCase.d.ts +7 -5
- package/features/GetFileContentsById/GetFileContentsByIdUseCase.js +8 -5
- package/features/GetFileContentsById/GetFileContentsByIdUseCase.js.map +1 -1
- package/features/GetFileContentsById/feature.js +2 -2
- package/features/GetFileContentsById/feature.js.map +1 -1
- package/features/GetFileContentsByKey/GetFileContentsByKeyUseCase.d.ts +7 -5
- package/features/GetFileContentsByKey/GetFileContentsByKeyUseCase.js +8 -5
- package/features/GetFileContentsByKey/GetFileContentsByKeyUseCase.js.map +1 -1
- package/features/GetFileContentsByKey/feature.js +2 -2
- package/features/GetFileContentsByKey/feature.js.map +1 -1
- package/features/GetUploadPayload/GetUploadPayloadUseCase.d.ts +6 -6
- package/features/GetUploadPayload/GetUploadPayloadUseCase.js +8 -9
- package/features/GetUploadPayload/GetUploadPayloadUseCase.js.map +1 -1
- package/features/GetUploadPayload/feature.js +2 -2
- package/features/GetUploadPayload/feature.js.map +1 -1
- package/graphql/ServerGraphQLSchema.d.ts +15 -0
- package/graphql/ServerGraphQLSchema.js +221 -0
- package/graphql/ServerGraphQLSchema.js.map +1 -0
- package/index.d.ts +1 -2
- package/index.js +1 -40
- package/package.json +13 -13
- package/routes/UploadPartRoute/UploadPartRoute.d.ts +14 -0
- package/routes/UploadPartRoute/UploadPartRoute.js +66 -0
- package/routes/UploadPartRoute/UploadPartRoute.js.map +1 -0
- package/routes/UploadPartRoute/feature.d.ts +4 -0
- package/routes/UploadPartRoute/feature.js +11 -0
- package/routes/UploadPartRoute/feature.js.map +1 -0
- package/routes/UploadSingleFileRoute/UploadSingleFileRoute.d.ts +14 -0
- package/routes/UploadSingleFileRoute/UploadSingleFileRoute.js +70 -0
- package/routes/UploadSingleFileRoute/UploadSingleFileRoute.js.map +1 -0
- package/routes/UploadSingleFileRoute/feature.d.ts +4 -0
- package/routes/UploadSingleFileRoute/feature.js +11 -0
- package/routes/UploadSingleFileRoute/feature.js.map +1 -0
- package/routes/utils.d.ts +20 -0
- package/routes/utils.js +62 -0
- package/routes/utils.js.map +1 -0
- package/index.js.map +0 -1
- package/routes/uploadRoutes.d.ts +0 -4
- package/routes/uploadRoutes.js +0 -130
- package/routes/uploadRoutes.js.map +0 -1
- package/utils/resolveServerUrl.d.ts +0 -2
- package/utils/resolveServerUrl.js +0 -10
- package/utils/resolveServerUrl.js.map +0 -1
package/assetDelivery/types.d.ts
CHANGED
|
@@ -1,8 +1,5 @@
|
|
|
1
|
-
import type { ImageFormat } from "@webiny/api-file-manager/features/assetDelivery/transformation/index.js";
|
|
2
1
|
export type AssetDeliveryParams = {
|
|
3
2
|
imageResizeWidths?: number[];
|
|
4
|
-
/** Per-format encoder quality (1-100). Merged over the built-in defaults. */
|
|
5
|
-
imageQuality?: Partial<Record<ImageFormat, number>>;
|
|
6
3
|
presignedUrlTtl?: number;
|
|
7
4
|
assetStreamingMaxSize?: number;
|
|
8
5
|
};
|
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
import { TaskDefinition } from "@webiny/api-core/features/task/TaskDefinition/index.js";
|
|
2
|
+
import { FileManagerServerConfig } from "../../features/FileManagerServerConfig/abstractions.js";
|
|
2
3
|
export interface CleanupStaleMultipartUploadsInput {
|
|
3
4
|
noop?: boolean;
|
|
4
5
|
}
|
|
5
6
|
declare class CleanupStaleMultipartUploadsTaskImpl implements TaskDefinition.Interface<CleanupStaleMultipartUploadsInput> {
|
|
7
|
+
private readonly config;
|
|
8
|
+
constructor(config: FileManagerServerConfig.Interface);
|
|
6
9
|
readonly id = "fileManagerCleanupStaleMultipartUploads";
|
|
7
10
|
readonly title = "Clean up stale multipart upload directories";
|
|
8
11
|
readonly description = "Removes multipart upload directories that are older than 24 hours.";
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { promises } from "node:fs";
|
|
2
2
|
import node_path from "node:path";
|
|
3
3
|
import { TaskDefinition } from "@webiny/api-core/features/task/TaskDefinition/index.js";
|
|
4
|
+
import { FileManagerServerConfig } from "../FileManagerServerConfig/abstractions.js";
|
|
4
5
|
const STALE_THRESHOLD_MS = 86400000;
|
|
5
6
|
async function readdirSafe(dirPath) {
|
|
6
7
|
try {
|
|
@@ -11,9 +12,22 @@ async function readdirSafe(dirPath) {
|
|
|
11
12
|
}
|
|
12
13
|
}
|
|
13
14
|
class CleanupStaleMultipartUploadsTaskImpl {
|
|
15
|
+
constructor(config){
|
|
16
|
+
this.config = config;
|
|
17
|
+
this.id = "fileManagerCleanupStaleMultipartUploads";
|
|
18
|
+
this.title = "Clean up stale multipart upload directories";
|
|
19
|
+
this.description = "Removes multipart upload directories that are older than 24 hours.";
|
|
20
|
+
this.maxIterations = 1;
|
|
21
|
+
this.isPrivate = true;
|
|
22
|
+
this.databaseLogs = false;
|
|
23
|
+
this.selfCleanup = [
|
|
24
|
+
"onSuccess",
|
|
25
|
+
"onAbort"
|
|
26
|
+
];
|
|
27
|
+
}
|
|
14
28
|
async run({ controller }) {
|
|
15
29
|
if (controller.runtime.isAborted()) return controller.response.aborted();
|
|
16
|
-
const storagePath =
|
|
30
|
+
const storagePath = this.config.storagePath;
|
|
17
31
|
const tenantsDir = node_path.join(storagePath, "tenants");
|
|
18
32
|
const now = Date.now();
|
|
19
33
|
const tenantDirs = await readdirSafe(tenantsDir);
|
|
@@ -36,22 +50,12 @@ class CleanupStaleMultipartUploadsTaskImpl {
|
|
|
36
50
|
}
|
|
37
51
|
return controller.response.done();
|
|
38
52
|
}
|
|
39
|
-
constructor(){
|
|
40
|
-
this.id = "fileManagerCleanupStaleMultipartUploads";
|
|
41
|
-
this.title = "Clean up stale multipart upload directories";
|
|
42
|
-
this.description = "Removes multipart upload directories that are older than 24 hours.";
|
|
43
|
-
this.maxIterations = 1;
|
|
44
|
-
this.isPrivate = true;
|
|
45
|
-
this.databaseLogs = false;
|
|
46
|
-
this.selfCleanup = [
|
|
47
|
-
"onSuccess",
|
|
48
|
-
"onAbort"
|
|
49
|
-
];
|
|
50
|
-
}
|
|
51
53
|
}
|
|
52
54
|
const CleanupStaleMultipartUploadsTaskDefinition = TaskDefinition.createImplementation({
|
|
53
55
|
implementation: CleanupStaleMultipartUploadsTaskImpl,
|
|
54
|
-
dependencies: [
|
|
56
|
+
dependencies: [
|
|
57
|
+
FileManagerServerConfig
|
|
58
|
+
]
|
|
55
59
|
});
|
|
56
60
|
export { CleanupStaleMultipartUploadsTaskDefinition };
|
|
57
61
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"features/CleanupStaleMultipartUploads/CleanupStaleMultipartUploadsTask.js","sources":["../../../src/features/CleanupStaleMultipartUploads/CleanupStaleMultipartUploadsTask.ts"],"sourcesContent":["import { promises as fs } from \"node:fs\";\nimport path from \"node:path\";\nimport { TaskDefinition } from \"@webiny/api-core/features/task/TaskDefinition/index.js\";\n\nexport interface CleanupStaleMultipartUploadsInput {\n /* Reserved for future use. */\n noop?: boolean;\n}\n\nconst STALE_THRESHOLD_MS = 24 * 60 * 60 * 1000;\n\n/* Returns directory entries or an empty array if the path does not exist. */\nasync function readdirSafe(dirPath: string): Promise<string[]> {\n try {\n return await fs.readdir(dirPath);\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === \"ENOENT\") {\n return [];\n }\n throw err;\n }\n}\n\nclass CleanupStaleMultipartUploadsTaskImpl implements TaskDefinition.Interface<CleanupStaleMultipartUploadsInput> {\n public readonly id = \"fileManagerCleanupStaleMultipartUploads\";\n public readonly title = \"Clean up stale multipart upload directories\";\n public readonly description =\n \"Removes multipart upload directories that are older than 24 hours.\";\n public readonly maxIterations = 1;\n public readonly isPrivate = true;\n public readonly databaseLogs = false;\n public readonly selfCleanup = [\"onSuccess\" as const, \"onAbort\" as const];\n\n public async run({\n controller\n }: TaskDefinition.RunParams<CleanupStaleMultipartUploadsInput>): Promise<\n TaskDefinition.Result<CleanupStaleMultipartUploadsInput>\n > {\n if (controller.runtime.isAborted()) {\n return controller.response.aborted();\n }\n\n const storagePath =
|
|
1
|
+
{"version":3,"file":"features/CleanupStaleMultipartUploads/CleanupStaleMultipartUploadsTask.js","sources":["../../../src/features/CleanupStaleMultipartUploads/CleanupStaleMultipartUploadsTask.ts"],"sourcesContent":["import { promises as fs } from \"node:fs\";\nimport path from \"node:path\";\nimport { TaskDefinition } from \"@webiny/api-core/features/task/TaskDefinition/index.js\";\nimport { FileManagerServerConfig } from \"~/features/FileManagerServerConfig/abstractions.js\";\n\nexport interface CleanupStaleMultipartUploadsInput {\n /* Reserved for future use. */\n noop?: boolean;\n}\n\nconst STALE_THRESHOLD_MS = 24 * 60 * 60 * 1000;\n\n/* Returns directory entries or an empty array if the path does not exist. */\nasync function readdirSafe(dirPath: string): Promise<string[]> {\n try {\n return await fs.readdir(dirPath);\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === \"ENOENT\") {\n return [];\n }\n throw err;\n }\n}\n\nclass CleanupStaleMultipartUploadsTaskImpl implements TaskDefinition.Interface<CleanupStaleMultipartUploadsInput> {\n public constructor(private readonly config: FileManagerServerConfig.Interface) {}\n public readonly id = \"fileManagerCleanupStaleMultipartUploads\";\n public readonly title = \"Clean up stale multipart upload directories\";\n public readonly description =\n \"Removes multipart upload directories that are older than 24 hours.\";\n public readonly maxIterations = 1;\n public readonly isPrivate = true;\n public readonly databaseLogs = false;\n public readonly selfCleanup = [\"onSuccess\" as const, \"onAbort\" as const];\n\n public async run({\n controller\n }: TaskDefinition.RunParams<CleanupStaleMultipartUploadsInput>): Promise<\n TaskDefinition.Result<CleanupStaleMultipartUploadsInput>\n > {\n if (controller.runtime.isAborted()) {\n return controller.response.aborted();\n }\n\n const storagePath = this.config.storagePath;\n const tenantsDir = path.join(storagePath, \"tenants\");\n const now = Date.now();\n\n const tenantDirs = await readdirSafe(tenantsDir);\n\n for (const tenantId of tenantDirs) {\n const multipartDir = path.join(tenantsDir, tenantId, \"multipart\");\n const uploadDirs = await readdirSafe(multipartDir);\n\n for (const uploadId of uploadDirs) {\n const uploadPath = path.join(multipartDir, uploadId);\n\n try {\n const stat = await fs.stat(uploadPath);\n const ageMs = now - stat.mtimeMs;\n\n if (ageMs > STALE_THRESHOLD_MS) {\n await fs.rm(uploadPath, { recursive: true, force: true });\n }\n } catch (err) {\n /* Skip entries that have already been removed or cannot be accessed. */\n if ((err as NodeJS.ErrnoException).code !== \"ENOENT\") {\n throw err;\n }\n }\n }\n }\n\n return controller.response.done();\n }\n}\n\nexport const CleanupStaleMultipartUploadsTaskDefinition = TaskDefinition.createImplementation({\n implementation: CleanupStaleMultipartUploadsTaskImpl,\n dependencies: [FileManagerServerConfig]\n});\n"],"names":["STALE_THRESHOLD_MS","readdirSafe","dirPath","fs","err","CleanupStaleMultipartUploadsTaskImpl","config","controller","storagePath","tenantsDir","path","now","Date","tenantDirs","tenantId","multipartDir","uploadDirs","uploadId","uploadPath","stat","ageMs","CleanupStaleMultipartUploadsTaskDefinition","TaskDefinition","FileManagerServerConfig"],"mappings":";;;;AAUA,MAAMA,qBAAqB;AAG3B,eAAeC,YAAYC,OAAe;IACtC,IAAI;QACA,OAAO,MAAMC,SAAAA,OAAU,CAACD;IAC5B,EAAE,OAAOE,KAAK;QACV,IAAKA,AAAuC,aAAvCA,IAA8B,IAAI,EACnC,OAAO,EAAE;QAEb,MAAMA;IACV;AACJ;AAEA,MAAMC;IACF,YAAoCC,MAAyC,CAAE;aAA3CA,MAAM,GAANA;aACpB,EAAE,GAAG;aACL,KAAK,GAAG;aACR,WAAW,GACvB;aACY,aAAa,GAAG;aAChB,SAAS,GAAG;aACZ,YAAY,GAAG;aACf,WAAW,GAAG;YAAC;YAAsB;SAAmB;IARQ;IAUhF,MAAa,IAAI,EACbC,UAAU,EACgD,EAE5D;QACE,IAAIA,WAAW,OAAO,CAAC,SAAS,IAC5B,OAAOA,WAAW,QAAQ,CAAC,OAAO;QAGtC,MAAMC,cAAc,IAAI,CAAC,MAAM,CAAC,WAAW;QAC3C,MAAMC,aAAaC,UAAAA,IAAS,CAACF,aAAa;QAC1C,MAAMG,MAAMC,KAAK,GAAG;QAEpB,MAAMC,aAAa,MAAMZ,YAAYQ;QAErC,KAAK,MAAMK,YAAYD,WAAY;YAC/B,MAAME,eAAeL,UAAAA,IAAS,CAACD,YAAYK,UAAU;YACrD,MAAME,aAAa,MAAMf,YAAYc;YAErC,KAAK,MAAME,YAAYD,WAAY;gBAC/B,MAAME,aAAaR,UAAAA,IAAS,CAACK,cAAcE;gBAE3C,IAAI;oBACA,MAAME,OAAO,MAAMhB,SAAAA,IAAO,CAACe;oBAC3B,MAAME,QAAQT,MAAMQ,KAAK,OAAO;oBAEhC,IAAIC,QAAQpB,oBACR,MAAMG,SAAAA,EAAK,CAACe,YAAY;wBAAE,WAAW;wBAAM,OAAO;oBAAK;gBAE/D,EAAE,OAAOd,KAAK;oBAEV,IAAKA,AAAuC,aAAvCA,IAA8B,IAAI,EACnC,MAAMA;gBAEd;YACJ;QACJ;QAEA,OAAOG,WAAW,QAAQ,CAAC,IAAI;IACnC;AACJ;AAEO,MAAMc,6CAA6CC,eAAe,oBAAoB,CAAC;IAC1F,gBAAgBjB;IAChB,cAAc;QAACkB;KAAwB;AAC3C"}
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import { TenantContext } from "@webiny/api-core/features/tenancy/TenantContext/index.js";
|
|
2
|
-
import { CompleteMultiPartUploadUseCase } from "@webiny/api-file-manager/features/upload/CompleteMultiPartUpload/index.js";
|
|
3
|
-
|
|
2
|
+
import { CompleteMultiPartUploadUseCase as CompleteMultiPartUploadUseCaseAbstraction } from "@webiny/api-file-manager/features/upload/CompleteMultiPartUpload/index.js";
|
|
3
|
+
import { FileManagerServerConfig } from "../../features/FileManagerServerConfig/abstractions.js";
|
|
4
|
+
declare class CompleteMultiPartUploadUseCaseImpl implements CompleteMultiPartUploadUseCaseAbstraction.Interface {
|
|
4
5
|
private readonly tenantContext;
|
|
5
|
-
|
|
6
|
-
|
|
6
|
+
private readonly config;
|
|
7
|
+
constructor(tenantContext: TenantContext.Interface, config: FileManagerServerConfig.Interface);
|
|
8
|
+
execute(params: CompleteMultiPartUploadUseCaseAbstraction.Params): Promise<void>;
|
|
7
9
|
}
|
|
8
|
-
export declare const
|
|
10
|
+
export declare const CompleteMultiPartUploadUseCase: typeof CompleteMultiPartUploadUseCaseImpl & {
|
|
9
11
|
__abstraction: import("@webiny/di").Abstraction<import("@webiny/api-file-manager/features/upload/CompleteMultiPartUpload/abstractions").ICompleteMultiPartUploadUseCase>;
|
|
10
12
|
};
|
|
11
13
|
export {};
|
|
@@ -2,13 +2,15 @@ import node_path from "node:path";
|
|
|
2
2
|
import { mkdir, readFile, readdir, rm, writeFile } from "node:fs/promises";
|
|
3
3
|
import { TenantContext } from "@webiny/api-core/features/tenancy/TenantContext/index.js";
|
|
4
4
|
import { CompleteMultiPartUploadUseCase } from "@webiny/api-file-manager/features/upload/CompleteMultiPartUpload/index.js";
|
|
5
|
+
import { FileManagerServerConfig } from "../FileManagerServerConfig/abstractions.js";
|
|
5
6
|
class CompleteMultiPartUploadUseCaseImpl {
|
|
6
|
-
constructor(tenantContext){
|
|
7
|
+
constructor(tenantContext, config){
|
|
7
8
|
this.tenantContext = tenantContext;
|
|
9
|
+
this.config = config;
|
|
8
10
|
}
|
|
9
11
|
async execute(params) {
|
|
10
12
|
const { fileKey, uploadId } = params;
|
|
11
|
-
const storagePath =
|
|
13
|
+
const storagePath = this.config.storagePath;
|
|
12
14
|
const tenant = this.tenantContext.getTenant();
|
|
13
15
|
assertNoTraversal(uploadId);
|
|
14
16
|
for (const seg of fileKey.split(/[\\/]/))assertNoTraversal(seg);
|
|
@@ -48,12 +50,13 @@ function assertPathContained(resolved, root) {
|
|
|
48
50
|
const normalizedRoot = node_path.resolve(root);
|
|
49
51
|
if (!normalized.startsWith(normalizedRoot + node_path.sep) && normalized !== normalizedRoot) throw new Error("Path escapes tenant root.");
|
|
50
52
|
}
|
|
51
|
-
const
|
|
53
|
+
const CompleteMultiPartUploadUseCase_CompleteMultiPartUploadUseCase = CompleteMultiPartUploadUseCase.createImplementation({
|
|
52
54
|
implementation: CompleteMultiPartUploadUseCaseImpl,
|
|
53
55
|
dependencies: [
|
|
54
|
-
TenantContext
|
|
56
|
+
TenantContext,
|
|
57
|
+
FileManagerServerConfig
|
|
55
58
|
]
|
|
56
59
|
});
|
|
57
|
-
export {
|
|
60
|
+
export { CompleteMultiPartUploadUseCase_CompleteMultiPartUploadUseCase as CompleteMultiPartUploadUseCase };
|
|
58
61
|
|
|
59
62
|
//# sourceMappingURL=CompleteMultiPartUploadUseCase.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"features/CompleteMultiPartUpload/CompleteMultiPartUploadUseCase.js","sources":["../../../src/features/CompleteMultiPartUpload/CompleteMultiPartUploadUseCase.ts"],"sourcesContent":["import path from \"node:path\";\nimport { mkdir } from \"node:fs/promises\";\nimport { readdir } from \"node:fs/promises\";\nimport { readFile } from \"node:fs/promises\";\nimport { writeFile } from \"node:fs/promises\";\nimport { rm } from \"node:fs/promises\";\nimport { TenantContext } from \"@webiny/api-core/features/tenancy/TenantContext/index.js\";\nimport { CompleteMultiPartUploadUseCase } from \"@webiny/api-file-manager/features/upload/CompleteMultiPartUpload/index.js\";\n\nclass CompleteMultiPartUploadUseCaseImpl
|
|
1
|
+
{"version":3,"file":"features/CompleteMultiPartUpload/CompleteMultiPartUploadUseCase.js","sources":["../../../src/features/CompleteMultiPartUpload/CompleteMultiPartUploadUseCase.ts"],"sourcesContent":["import path from \"node:path\";\nimport { mkdir } from \"node:fs/promises\";\nimport { readdir } from \"node:fs/promises\";\nimport { readFile } from \"node:fs/promises\";\nimport { writeFile } from \"node:fs/promises\";\nimport { rm } from \"node:fs/promises\";\nimport { TenantContext } from \"@webiny/api-core/features/tenancy/TenantContext/index.js\";\nimport { CompleteMultiPartUploadUseCase as CompleteMultiPartUploadUseCaseAbstraction } from \"@webiny/api-file-manager/features/upload/CompleteMultiPartUpload/index.js\";\nimport { FileManagerServerConfig } from \"~/features/FileManagerServerConfig/abstractions.js\";\n\nclass CompleteMultiPartUploadUseCaseImpl\n implements CompleteMultiPartUploadUseCaseAbstraction.Interface\n{\n public constructor(\n private readonly tenantContext: TenantContext.Interface,\n private readonly config: FileManagerServerConfig.Interface\n ) {}\n\n public async execute(params: CompleteMultiPartUploadUseCaseAbstraction.Params): Promise<void> {\n const { fileKey, uploadId } = params;\n const storagePath = this.config.storagePath;\n const tenant = this.tenantContext.getTenant();\n\n assertNoTraversal(uploadId);\n for (const seg of fileKey.split(/[\\\\/]/)) {\n assertNoTraversal(seg);\n }\n\n const tenantRoot = path.resolve(path.join(storagePath, \"tenants\", tenant.id, \"files\"));\n const destPath = path.resolve(path.join(tenantRoot, fileKey));\n assertPathContained(destPath, tenantRoot);\n\n const multipartDir = path.join(storagePath, \"tenants\", tenant.id, \"multipart\", uploadId);\n\n const entries = await readdir(multipartDir);\n const sorted = entries\n .filter(name => name.startsWith(\"part-\"))\n .sort((a, b) => {\n const numA = parseInt(a.replace(\"part-\", \"\"), 10);\n const numB = parseInt(b.replace(\"part-\", \"\"), 10);\n return numA - numB;\n });\n\n const destDir = path.dirname(destPath);\n await mkdir(destDir, { recursive: true });\n\n const buffers: Buffer[] = [];\n for (const partName of sorted) {\n const partPath = path.join(multipartDir, partName);\n const partData = await readFile(partPath);\n buffers.push(partData);\n }\n\n const finalBuffer = Buffer.concat(buffers);\n await writeFile(destPath, finalBuffer);\n\n await rm(multipartDir, { recursive: true, force: true });\n }\n}\n\nfunction assertNoTraversal(segment: string): void {\n if (segment.includes(\"..\") || segment.includes(\"/\") || segment.includes(\"\\\\\")) {\n throw new Error(\"Invalid path segment.\");\n }\n}\n\nfunction assertPathContained(resolved: string, root: string): void {\n const normalized = path.resolve(resolved);\n const normalizedRoot = path.resolve(root);\n if (!normalized.startsWith(normalizedRoot + path.sep) && normalized !== normalizedRoot) {\n throw new Error(\"Path escapes tenant root.\");\n }\n}\n\nexport const CompleteMultiPartUploadUseCase =\n CompleteMultiPartUploadUseCaseAbstraction.createImplementation({\n implementation: CompleteMultiPartUploadUseCaseImpl,\n dependencies: [TenantContext, FileManagerServerConfig]\n });\n"],"names":["CompleteMultiPartUploadUseCaseImpl","tenantContext","config","params","fileKey","uploadId","storagePath","tenant","assertNoTraversal","seg","tenantRoot","path","destPath","assertPathContained","multipartDir","entries","readdir","sorted","name","a","b","numA","parseInt","numB","destDir","mkdir","buffers","partName","partPath","partData","readFile","finalBuffer","Buffer","writeFile","rm","segment","Error","resolved","root","normalized","normalizedRoot","CompleteMultiPartUploadUseCase","CompleteMultiPartUploadUseCaseAbstraction","TenantContext","FileManagerServerConfig"],"mappings":";;;;;AAUA,MAAMA;IAGF,YACqBC,aAAsC,EACtCC,MAAyC,CAC5D;aAFmBD,aAAa,GAAbA;aACAC,MAAM,GAANA;IAClB;IAEH,MAAa,QAAQC,MAAwD,EAAiB;QAC1F,MAAM,EAAEC,OAAO,EAAEC,QAAQ,EAAE,GAAGF;QAC9B,MAAMG,cAAc,IAAI,CAAC,MAAM,CAAC,WAAW;QAC3C,MAAMC,SAAS,IAAI,CAAC,aAAa,CAAC,SAAS;QAE3CC,kBAAkBH;QAClB,KAAK,MAAMI,OAAOL,QAAQ,KAAK,CAAC,SAC5BI,kBAAkBC;QAGtB,MAAMC,aAAaC,UAAAA,OAAY,CAACA,UAAAA,IAAS,CAACL,aAAa,WAAWC,OAAO,EAAE,EAAE;QAC7E,MAAMK,WAAWD,UAAAA,OAAY,CAACA,UAAAA,IAAS,CAACD,YAAYN;QACpDS,oBAAoBD,UAAUF;QAE9B,MAAMI,eAAeH,UAAAA,IAAS,CAACL,aAAa,WAAWC,OAAO,EAAE,EAAE,aAAaF;QAE/E,MAAMU,UAAU,MAAMC,QAAQF;QAC9B,MAAMG,SAASF,QACV,MAAM,CAACG,CAAAA,OAAQA,KAAK,UAAU,CAAC,UAC/B,IAAI,CAAC,CAACC,GAAGC;YACN,MAAMC,OAAOC,SAASH,EAAE,OAAO,CAAC,SAAS,KAAK;YAC9C,MAAMI,OAAOD,SAASF,EAAE,OAAO,CAAC,SAAS,KAAK;YAC9C,OAAOC,OAAOE;QAClB;QAEJ,MAAMC,UAAUb,UAAAA,OAAY,CAACC;QAC7B,MAAMa,MAAMD,SAAS;YAAE,WAAW;QAAK;QAEvC,MAAME,UAAoB,EAAE;QAC5B,KAAK,MAAMC,YAAYV,OAAQ;YAC3B,MAAMW,WAAWjB,UAAAA,IAAS,CAACG,cAAca;YACzC,MAAME,WAAW,MAAMC,SAASF;YAChCF,QAAQ,IAAI,CAACG;QACjB;QAEA,MAAME,cAAcC,OAAO,MAAM,CAACN;QAClC,MAAMO,UAAUrB,UAAUmB;QAE1B,MAAMG,GAAGpB,cAAc;YAAE,WAAW;YAAM,OAAO;QAAK;IAC1D;AACJ;AAEA,SAASN,kBAAkB2B,OAAe;IACtC,IAAIA,QAAQ,QAAQ,CAAC,SAASA,QAAQ,QAAQ,CAAC,QAAQA,QAAQ,QAAQ,CAAC,OACpE,MAAM,IAAIC,MAAM;AAExB;AAEA,SAASvB,oBAAoBwB,QAAgB,EAAEC,IAAY;IACvD,MAAMC,aAAa5B,UAAAA,OAAY,CAAC0B;IAChC,MAAMG,iBAAiB7B,UAAAA,OAAY,CAAC2B;IACpC,IAAI,CAACC,WAAW,UAAU,CAACC,iBAAiB7B,UAAAA,GAAQ,KAAK4B,eAAeC,gBACpE,MAAM,IAAIJ,MAAM;AAExB;AAEO,MAAMK,gEACTC,+BAAAA,oBAA8D,CAAC;IAC3D,gBAAgB1C;IAChB,cAAc;QAAC2C;QAAeC;KAAwB;AAC1D"}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { createFeature } from "@webiny/feature/api";
|
|
2
|
-
import {
|
|
2
|
+
import { CompleteMultiPartUploadUseCase } from "./CompleteMultiPartUploadUseCase.js";
|
|
3
3
|
const CompleteMultiPartUploadFeature = createFeature({
|
|
4
4
|
name: "FileManagerServer/CompleteMultiPartUpload",
|
|
5
5
|
register (container) {
|
|
6
|
-
container.register(
|
|
6
|
+
container.register(CompleteMultiPartUploadUseCase);
|
|
7
7
|
}
|
|
8
8
|
});
|
|
9
9
|
export { CompleteMultiPartUploadFeature };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"features/CompleteMultiPartUpload/feature.js","sources":["../../../src/features/CompleteMultiPartUpload/feature.ts"],"sourcesContent":["import { createFeature } from \"@webiny/feature/api\";\nimport {
|
|
1
|
+
{"version":3,"file":"features/CompleteMultiPartUpload/feature.js","sources":["../../../src/features/CompleteMultiPartUpload/feature.ts"],"sourcesContent":["import { createFeature } from \"@webiny/feature/api\";\nimport { CompleteMultiPartUploadUseCase } from \"./CompleteMultiPartUploadUseCase.js\";\n\nexport const CompleteMultiPartUploadFeature = createFeature({\n name: \"FileManagerServer/CompleteMultiPartUpload\",\n register(container) {\n container.register(CompleteMultiPartUploadUseCase);\n }\n});\n"],"names":["CompleteMultiPartUploadFeature","createFeature","container","CompleteMultiPartUploadUseCase"],"mappings":";;AAGO,MAAMA,iCAAiCC,cAAc;IACxD,MAAM;IACN,UAASC,SAAS;QACdA,UAAU,QAAQ,CAACC;IACvB;AACJ"}
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import { TenantContext } from "@webiny/api-core/features/tenancy/TenantContext/index.js";
|
|
2
|
-
import {
|
|
3
|
-
import { CreateMultiPartUploadUseCase } from "@webiny/api-file-manager/features/upload/CreateMultiPartUpload/index.js";
|
|
2
|
+
import { CreateMultiPartUploadUseCase as CreateMultiPartUploadUseCaseAbstraction } from "@webiny/api-file-manager/features/upload/CreateMultiPartUpload/index.js";
|
|
4
3
|
import type { CreateMultiPartUploadResult } from "@webiny/api-file-manager/features/upload/types.js";
|
|
5
|
-
|
|
4
|
+
import { FileManagerServerConfig } from "../../features/FileManagerServerConfig/abstractions.js";
|
|
5
|
+
declare class CreateMultiPartUploadUseCaseImpl implements CreateMultiPartUploadUseCaseAbstraction.Interface {
|
|
6
6
|
private readonly tenantContext;
|
|
7
|
-
private readonly
|
|
8
|
-
constructor(tenantContext: TenantContext.Interface,
|
|
9
|
-
execute(params:
|
|
7
|
+
private readonly config;
|
|
8
|
+
constructor(tenantContext: TenantContext.Interface, config: FileManagerServerConfig.Interface);
|
|
9
|
+
execute(params: CreateMultiPartUploadUseCaseAbstraction.Params): Promise<CreateMultiPartUploadResult>;
|
|
10
10
|
}
|
|
11
|
-
export declare const
|
|
11
|
+
export declare const CreateMultiPartUploadUseCase: typeof CreateMultiPartUploadUseCaseImpl & {
|
|
12
12
|
__abstraction: import("@webiny/di").Abstraction<import("@webiny/api-file-manager/features/upload/CreateMultiPartUpload/abstractions").ICreateMultiPartUploadUseCase>;
|
|
13
13
|
};
|
|
14
14
|
export {};
|
|
@@ -2,26 +2,25 @@ import node_path from "node:path";
|
|
|
2
2
|
import { mkdir } from "node:fs/promises";
|
|
3
3
|
import { mdbid } from "@webiny/utils";
|
|
4
4
|
import { TenantContext } from "@webiny/api-core/features/tenancy/TenantContext/index.js";
|
|
5
|
-
import { Request } from "@webiny/handler/abstractions/Request.js";
|
|
6
5
|
import { CreateMultiPartUploadUseCase } from "@webiny/api-file-manager/features/upload/CreateMultiPartUpload/index.js";
|
|
7
6
|
import { createUploadToken } from "../../utils/uploadToken.js";
|
|
8
|
-
import {
|
|
7
|
+
import { FileManagerServerConfig } from "../FileManagerServerConfig/abstractions.js";
|
|
9
8
|
class CreateMultiPartUploadUseCaseImpl {
|
|
10
|
-
constructor(tenantContext,
|
|
9
|
+
constructor(tenantContext, config){
|
|
11
10
|
this.tenantContext = tenantContext;
|
|
12
|
-
this.
|
|
11
|
+
this.config = config;
|
|
13
12
|
}
|
|
14
13
|
async execute(params) {
|
|
15
14
|
const { file, numberOfParts } = params;
|
|
16
|
-
const storagePath =
|
|
15
|
+
const storagePath = this.config.storagePath;
|
|
17
16
|
const tenant = this.tenantContext.getTenant();
|
|
18
|
-
const serverUrl =
|
|
17
|
+
const serverUrl = this.config.apiUrl;
|
|
19
18
|
const uploadId = mdbid();
|
|
20
19
|
const multipartDir = node_path.join(storagePath, "tenants", tenant.id, "multipart", uploadId);
|
|
21
20
|
await mkdir(multipartDir, {
|
|
22
21
|
recursive: true
|
|
23
22
|
});
|
|
24
|
-
const secret =
|
|
23
|
+
const secret = this.config.uploadSecret;
|
|
25
24
|
const expiresAt = Date.now() + 86400000;
|
|
26
25
|
const parts = Array.from({
|
|
27
26
|
length: numberOfParts
|
|
@@ -47,13 +46,13 @@ class CreateMultiPartUploadUseCaseImpl {
|
|
|
47
46
|
};
|
|
48
47
|
}
|
|
49
48
|
}
|
|
50
|
-
const
|
|
49
|
+
const CreateMultiPartUploadUseCase_CreateMultiPartUploadUseCase = CreateMultiPartUploadUseCase.createImplementation({
|
|
51
50
|
implementation: CreateMultiPartUploadUseCaseImpl,
|
|
52
51
|
dependencies: [
|
|
53
52
|
TenantContext,
|
|
54
|
-
|
|
53
|
+
FileManagerServerConfig
|
|
55
54
|
]
|
|
56
55
|
});
|
|
57
|
-
export {
|
|
56
|
+
export { CreateMultiPartUploadUseCase_CreateMultiPartUploadUseCase as CreateMultiPartUploadUseCase };
|
|
58
57
|
|
|
59
58
|
//# sourceMappingURL=CreateMultiPartUploadUseCase.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"features/CreateMultiPartUpload/CreateMultiPartUploadUseCase.js","sources":["../../../src/features/CreateMultiPartUpload/CreateMultiPartUploadUseCase.ts"],"sourcesContent":["import path from \"node:path\";\nimport { mkdir } from \"node:fs/promises\";\nimport { mdbid } from \"@webiny/utils\";\nimport { TenantContext } from \"@webiny/api-core/features/tenancy/TenantContext/index.js\";\nimport {
|
|
1
|
+
{"version":3,"file":"features/CreateMultiPartUpload/CreateMultiPartUploadUseCase.js","sources":["../../../src/features/CreateMultiPartUpload/CreateMultiPartUploadUseCase.ts"],"sourcesContent":["import path from \"node:path\";\nimport { mkdir } from \"node:fs/promises\";\nimport { mdbid } from \"@webiny/utils\";\nimport { TenantContext } from \"@webiny/api-core/features/tenancy/TenantContext/index.js\";\nimport { CreateMultiPartUploadUseCase as CreateMultiPartUploadUseCaseAbstraction } from \"@webiny/api-file-manager/features/upload/CreateMultiPartUpload/index.js\";\nimport type { CreateMultiPartUploadResult } from \"@webiny/api-file-manager/features/upload/types.js\";\nimport { createUploadToken } from \"~/utils/uploadToken.js\";\nimport { FileManagerServerConfig } from \"~/features/FileManagerServerConfig/abstractions.js\";\n\nclass CreateMultiPartUploadUseCaseImpl\n implements CreateMultiPartUploadUseCaseAbstraction.Interface\n{\n public constructor(\n private readonly tenantContext: TenantContext.Interface,\n private readonly config: FileManagerServerConfig.Interface\n ) {}\n\n public async execute(\n params: CreateMultiPartUploadUseCaseAbstraction.Params\n ): Promise<CreateMultiPartUploadResult> {\n const { file, numberOfParts } = params;\n const storagePath = this.config.storagePath;\n const tenant = this.tenantContext.getTenant();\n const serverUrl = this.config.apiUrl;\n\n const uploadId = mdbid();\n\n const multipartDir = path.join(storagePath, \"tenants\", tenant.id, \"multipart\", uploadId);\n await mkdir(multipartDir, { recursive: true });\n\n const secret = this.config.uploadSecret;\n const expiresAt = Date.now() + 86_400_000; /* 24h */\n\n const parts = Array.from({ length: numberOfParts }, (_, index) => {\n const partNumber = index + 1;\n\n const token = createUploadToken(\n {\n key: `tenants/${tenant.id}/multipart/${uploadId}/part-${partNumber}`,\n tenantId: tenant.id,\n expiresAt,\n uploadMinFileSize: 0,\n uploadMaxFileSize: 1_099_511_627_776\n },\n secret\n );\n\n const url = `${serverUrl}/webiny-file-upload/parts?uploadId=${uploadId}&partNumber=${partNumber}&token=${token}`;\n\n return { partNumber, url };\n });\n\n return { file, uploadId, parts };\n }\n}\n\nexport const CreateMultiPartUploadUseCase =\n CreateMultiPartUploadUseCaseAbstraction.createImplementation({\n implementation: CreateMultiPartUploadUseCaseImpl,\n dependencies: [TenantContext, FileManagerServerConfig]\n });\n"],"names":["CreateMultiPartUploadUseCaseImpl","tenantContext","config","params","file","numberOfParts","storagePath","tenant","serverUrl","uploadId","mdbid","multipartDir","path","mkdir","secret","expiresAt","Date","parts","Array","_","index","partNumber","token","createUploadToken","url","CreateMultiPartUploadUseCase","CreateMultiPartUploadUseCaseAbstraction","TenantContext","FileManagerServerConfig"],"mappings":";;;;;;;AASA,MAAMA;IAGF,YACqBC,aAAsC,EACtCC,MAAyC,CAC5D;aAFmBD,aAAa,GAAbA;aACAC,MAAM,GAANA;IAClB;IAEH,MAAa,QACTC,MAAsD,EAClB;QACpC,MAAM,EAAEC,IAAI,EAAEC,aAAa,EAAE,GAAGF;QAChC,MAAMG,cAAc,IAAI,CAAC,MAAM,CAAC,WAAW;QAC3C,MAAMC,SAAS,IAAI,CAAC,aAAa,CAAC,SAAS;QAC3C,MAAMC,YAAY,IAAI,CAAC,MAAM,CAAC,MAAM;QAEpC,MAAMC,WAAWC;QAEjB,MAAMC,eAAeC,UAAAA,IAAS,CAACN,aAAa,WAAWC,OAAO,EAAE,EAAE,aAAaE;QAC/E,MAAMI,MAAMF,cAAc;YAAE,WAAW;QAAK;QAE5C,MAAMG,SAAS,IAAI,CAAC,MAAM,CAAC,YAAY;QACvC,MAAMC,YAAYC,KAAK,GAAG,KAAK;QAE/B,MAAMC,QAAQC,MAAM,IAAI,CAAC;YAAE,QAAQb;QAAc,GAAG,CAACc,GAAGC;YACpD,MAAMC,aAAaD,QAAQ;YAE3B,MAAME,QAAQC,kBACV;gBACI,KAAK,CAAC,QAAQ,EAAEhB,OAAO,EAAE,CAAC,WAAW,EAAEE,SAAS,MAAM,EAAEY,YAAY;gBACpE,UAAUd,OAAO,EAAE;gBACnBQ;gBACA,mBAAmB;gBACnB,mBAAmB;YACvB,GACAD;YAGJ,MAAMU,MAAM,GAAGhB,UAAU,mCAAmC,EAAEC,SAAS,YAAY,EAAEY,WAAW,OAAO,EAAEC,OAAO;YAEhH,OAAO;gBAAED;gBAAYG;YAAI;QAC7B;QAEA,OAAO;YAAEpB;YAAMK;YAAUQ;QAAM;IACnC;AACJ;AAEO,MAAMQ,4DACTC,6BAAAA,oBAA4D,CAAC;IACzD,gBAAgB1B;IAChB,cAAc;QAAC2B;QAAeC;KAAwB;AAC1D"}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { createFeature } from "@webiny/feature/api";
|
|
2
|
-
import {
|
|
2
|
+
import { CreateMultiPartUploadUseCase } from "./CreateMultiPartUploadUseCase.js";
|
|
3
3
|
const CreateMultiPartUploadFeature = createFeature({
|
|
4
4
|
name: "FileManagerServer/CreateMultiPartUpload",
|
|
5
5
|
register (container) {
|
|
6
|
-
container.register(
|
|
6
|
+
container.register(CreateMultiPartUploadUseCase);
|
|
7
7
|
}
|
|
8
8
|
});
|
|
9
9
|
export { CreateMultiPartUploadFeature };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"features/CreateMultiPartUpload/feature.js","sources":["../../../src/features/CreateMultiPartUpload/feature.ts"],"sourcesContent":["import { createFeature } from \"@webiny/feature/api\";\nimport {
|
|
1
|
+
{"version":3,"file":"features/CreateMultiPartUpload/feature.js","sources":["../../../src/features/CreateMultiPartUpload/feature.ts"],"sourcesContent":["import { createFeature } from \"@webiny/feature/api\";\nimport { CreateMultiPartUploadUseCase } from \"./CreateMultiPartUploadUseCase.js\";\n\nexport const CreateMultiPartUploadFeature = createFeature({\n name: \"FileManagerServer/CreateMultiPartUpload\",\n register(container) {\n container.register(CreateMultiPartUploadUseCase);\n }\n});\n"],"names":["CreateMultiPartUploadFeature","createFeature","container","CreateMultiPartUploadUseCase"],"mappings":";;AAGO,MAAMA,+BAA+BC,cAAc;IACtD,MAAM;IACN,UAASC,SAAS;QACdA,UAAU,QAAQ,CAACC;IACvB;AACJ"}
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import { FileAfterDeleteEventHandler } from "@webiny/api-file-manager/features/file/DeleteFile/events.js";
|
|
2
2
|
import { GlobalKeyValueStore } from "@webiny/api-core/features/keyValueStore/index.js";
|
|
3
3
|
import { TenantContext } from "@webiny/api-core/features/tenancy/TenantContext/index.js";
|
|
4
|
+
import { FileManagerServerConfig } from "../../features/FileManagerServerConfig/abstractions.js";
|
|
4
5
|
declare class DeleteFileFromDiskHandlerImpl implements FileAfterDeleteEventHandler.Interface {
|
|
5
6
|
private readonly tenantContext;
|
|
6
7
|
private readonly keyValueStore;
|
|
7
|
-
|
|
8
|
+
private readonly config;
|
|
9
|
+
constructor(tenantContext: TenantContext.Interface, keyValueStore: GlobalKeyValueStore.Interface, config: FileManagerServerConfig.Interface);
|
|
8
10
|
handle(event: FileAfterDeleteEventHandler.Event): Promise<void>;
|
|
9
11
|
}
|
|
10
12
|
export declare const DeleteFileFromDiskHandler: typeof DeleteFileFromDiskHandlerImpl & {
|
|
@@ -2,15 +2,17 @@ import { promises } from "node:fs";
|
|
|
2
2
|
import { FileAfterDeleteEventHandler } from "@webiny/api-file-manager/features/file/DeleteFile/events.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
|
+
import { FileManagerServerConfig } from "../FileManagerServerConfig/abstractions.js";
|
|
5
6
|
class DeleteFileFromDiskHandlerImpl {
|
|
6
|
-
constructor(tenantContext, keyValueStore){
|
|
7
|
+
constructor(tenantContext, keyValueStore, config){
|
|
7
8
|
this.tenantContext = tenantContext;
|
|
8
9
|
this.keyValueStore = keyValueStore;
|
|
10
|
+
this.config = config;
|
|
9
11
|
}
|
|
10
12
|
async handle(event) {
|
|
11
13
|
const { file } = event.payload;
|
|
12
14
|
const tenant = this.tenantContext.getTenant();
|
|
13
|
-
const storagePath =
|
|
15
|
+
const storagePath = this.config.storagePath;
|
|
14
16
|
const folderPath = `${storagePath}/tenants/${tenant.id}/files/${file.id}`;
|
|
15
17
|
await promises.rm(folderPath, {
|
|
16
18
|
recursive: true,
|
|
@@ -23,7 +25,8 @@ const DeleteFileFromDiskHandler = FileAfterDeleteEventHandler.createImplementati
|
|
|
23
25
|
implementation: DeleteFileFromDiskHandlerImpl,
|
|
24
26
|
dependencies: [
|
|
25
27
|
TenantContext,
|
|
26
|
-
GlobalKeyValueStore
|
|
28
|
+
GlobalKeyValueStore,
|
|
29
|
+
FileManagerServerConfig
|
|
27
30
|
]
|
|
28
31
|
});
|
|
29
32
|
export { DeleteFileFromDiskHandler };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"features/DeleteFileFromDisk/DeleteFileFromDiskHandler.js","sources":["../../../src/features/DeleteFileFromDisk/DeleteFileFromDiskHandler.ts"],"sourcesContent":["import { promises as fs } from \"node:fs\";\nimport { FileAfterDeleteEventHandler } from \"@webiny/api-file-manager/features/file/DeleteFile/events.js\";\nimport { GlobalKeyValueStore } from \"@webiny/api-core/features/keyValueStore/index.js\";\nimport { TenantContext } from \"@webiny/api-core/features/tenancy/TenantContext/index.js\";\n\nclass DeleteFileFromDiskHandlerImpl implements FileAfterDeleteEventHandler.Interface {\n constructor(\n private readonly tenantContext: TenantContext.Interface,\n private readonly 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 const storagePath =
|
|
1
|
+
{"version":3,"file":"features/DeleteFileFromDisk/DeleteFileFromDiskHandler.js","sources":["../../../src/features/DeleteFileFromDisk/DeleteFileFromDiskHandler.ts"],"sourcesContent":["import { promises as fs } from \"node:fs\";\nimport { FileAfterDeleteEventHandler } from \"@webiny/api-file-manager/features/file/DeleteFile/events.js\";\nimport { GlobalKeyValueStore } from \"@webiny/api-core/features/keyValueStore/index.js\";\nimport { TenantContext } from \"@webiny/api-core/features/tenancy/TenantContext/index.js\";\nimport { FileManagerServerConfig } from \"~/features/FileManagerServerConfig/abstractions.js\";\n\nclass DeleteFileFromDiskHandlerImpl implements FileAfterDeleteEventHandler.Interface {\n constructor(\n private readonly tenantContext: TenantContext.Interface,\n private readonly keyValueStore: GlobalKeyValueStore.Interface,\n private readonly config: FileManagerServerConfig.Interface\n ) {}\n\n async handle(event: FileAfterDeleteEventHandler.Event): Promise<void> {\n const { file } = event.payload;\n const tenant = this.tenantContext.getTenant();\n const storagePath = this.config.storagePath;\n const folderPath = `${storagePath}/tenants/${tenant.id}/files/${file.id}`;\n\n /* Delete the file folder from local disk. */\n await fs.rm(folderPath, { recursive: true, force: true });\n\n /* Delete file metadata from the key-value store. */\n await this.keyValueStore.delete(`FileManager/File/${file.id}/Metadata`);\n }\n}\n\nexport const DeleteFileFromDiskHandler = FileAfterDeleteEventHandler.createImplementation({\n implementation: DeleteFileFromDiskHandlerImpl,\n dependencies: [TenantContext, GlobalKeyValueStore, FileManagerServerConfig]\n});\n"],"names":["DeleteFileFromDiskHandlerImpl","tenantContext","keyValueStore","config","event","file","tenant","storagePath","folderPath","fs","DeleteFileFromDiskHandler","FileAfterDeleteEventHandler","TenantContext","GlobalKeyValueStore","FileManagerServerConfig"],"mappings":";;;;;AAMA,MAAMA;IACF,YACqBC,aAAsC,EACtCC,aAA4C,EAC5CC,MAAyC,CAC5D;aAHmBF,aAAa,GAAbA;aACAC,aAAa,GAAbA;aACAC,MAAM,GAANA;IAClB;IAEH,MAAM,OAAOC,KAAwC,EAAiB;QAClE,MAAM,EAAEC,IAAI,EAAE,GAAGD,MAAM,OAAO;QAC9B,MAAME,SAAS,IAAI,CAAC,aAAa,CAAC,SAAS;QAC3C,MAAMC,cAAc,IAAI,CAAC,MAAM,CAAC,WAAW;QAC3C,MAAMC,aAAa,GAAGD,YAAY,SAAS,EAAED,OAAO,EAAE,CAAC,OAAO,EAAED,KAAK,EAAE,EAAE;QAGzE,MAAMI,SAAAA,EAAK,CAACD,YAAY;YAAE,WAAW;YAAM,OAAO;QAAK;QAGvD,MAAM,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,iBAAiB,EAAEH,KAAK,EAAE,CAAC,SAAS,CAAC;IAC1E;AACJ;AAEO,MAAMK,4BAA4BC,4BAA4B,oBAAoB,CAAC;IACtF,gBAAgBX;IAChB,cAAc;QAACY;QAAeC;QAAqBC;KAAwB;AAC/E"}
|
|
@@ -2,9 +2,11 @@ import { TaskDefinition } from "@webiny/api-core/features/task/TaskDefinition/in
|
|
|
2
2
|
import { UpdateFileUseCase } from "@webiny/api-file-manager/features/file/UpdateFile/index.js";
|
|
3
3
|
import { MetadataReader } from "@webiny/api-file-manager/features/upload/ReadFileMetadata/abstractions.js";
|
|
4
4
|
import type { ExtractMetadataInput } from "@webiny/api-file-manager/features/extractMetadata/ExtractMetadataInput.js";
|
|
5
|
+
import { FileManagerServerConfig } from "../../features/FileManagerServerConfig/abstractions.js";
|
|
5
6
|
declare class ExtractMetadataTaskImpl implements TaskDefinition.Interface<ExtractMetadataInput> {
|
|
6
7
|
private readonly metadataReader;
|
|
7
8
|
private readonly updateFileUseCase;
|
|
9
|
+
private readonly config;
|
|
8
10
|
readonly id = "fileManagerExtractMetadata";
|
|
9
11
|
readonly title = "Extract image metadata (dimensions, EXIF, IPTC)";
|
|
10
12
|
readonly description = "A task to extract metadata from uploaded image files";
|
|
@@ -12,7 +14,7 @@ declare class ExtractMetadataTaskImpl implements TaskDefinition.Interface<Extrac
|
|
|
12
14
|
readonly isPrivate = true;
|
|
13
15
|
readonly databaseLogs = false;
|
|
14
16
|
readonly selfCleanup: ("onAbort" | "onSuccess")[];
|
|
15
|
-
constructor(metadataReader: MetadataReader.Interface, updateFileUseCase: UpdateFileUseCase.Interface);
|
|
17
|
+
constructor(metadataReader: MetadataReader.Interface, updateFileUseCase: UpdateFileUseCase.Interface, config: FileManagerServerConfig.Interface);
|
|
16
18
|
run({ input, controller }: TaskDefinition.RunParams<ExtractMetadataInput>): Promise<TaskDefinition.Result<ExtractMetadataInput>>;
|
|
17
19
|
private cleanValues;
|
|
18
20
|
}
|
|
@@ -2,10 +2,12 @@ import { promises } from "node:fs";
|
|
|
2
2
|
import { TaskDefinition } from "@webiny/api-core/features/task/TaskDefinition/index.js";
|
|
3
3
|
import { UpdateFileUseCase } from "@webiny/api-file-manager/features/file/UpdateFile/index.js";
|
|
4
4
|
import { MetadataReader } from "@webiny/api-file-manager/features/upload/ReadFileMetadata/abstractions.js";
|
|
5
|
+
import { FileManagerServerConfig } from "../FileManagerServerConfig/abstractions.js";
|
|
5
6
|
class ExtractMetadataTaskImpl {
|
|
6
|
-
constructor(metadataReader, updateFileUseCase){
|
|
7
|
+
constructor(metadataReader, updateFileUseCase, config){
|
|
7
8
|
this.metadataReader = metadataReader;
|
|
8
9
|
this.updateFileUseCase = updateFileUseCase;
|
|
10
|
+
this.config = config;
|
|
9
11
|
this.id = "fileManagerExtractMetadata";
|
|
10
12
|
this.title = "Extract image metadata (dimensions, EXIF, IPTC)";
|
|
11
13
|
this.description = "A task to extract metadata from uploaded image files";
|
|
@@ -24,7 +26,7 @@ class ExtractMetadataTaskImpl {
|
|
|
24
26
|
message: `File metadata not found for file ID: ${input.fileId}`
|
|
25
27
|
});
|
|
26
28
|
if (!fileMetadata.contentType.startsWith("image/")) return controller.response.done();
|
|
27
|
-
const storagePath =
|
|
29
|
+
const storagePath = this.config.storagePath;
|
|
28
30
|
const filePath = `${storagePath}/${fileMetadata.bucketKey}`;
|
|
29
31
|
try {
|
|
30
32
|
const buffer = await promises.readFile(filePath);
|
|
@@ -73,7 +75,8 @@ const ExtractMetadataTaskDefinition = TaskDefinition.createImplementation({
|
|
|
73
75
|
implementation: ExtractMetadataTaskImpl,
|
|
74
76
|
dependencies: [
|
|
75
77
|
MetadataReader,
|
|
76
|
-
UpdateFileUseCase
|
|
78
|
+
UpdateFileUseCase,
|
|
79
|
+
FileManagerServerConfig
|
|
77
80
|
]
|
|
78
81
|
});
|
|
79
82
|
export { ExtractMetadataTaskDefinition };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"features/ExtractMetadata/ExtractMetadataTask.js","sources":["../../../src/features/ExtractMetadata/ExtractMetadataTask.ts"],"sourcesContent":["import { promises as fs } from \"node:fs\";\nimport type { ExifTags } from \"exifreader\";\nimport { TaskDefinition } from \"@webiny/api-core/features/task/TaskDefinition/index.js\";\nimport { UpdateFileUseCase } from \"@webiny/api-file-manager/features/file/UpdateFile/index.js\";\nimport { MetadataReader } from \"@webiny/api-file-manager/features/upload/ReadFileMetadata/abstractions.js\";\nimport type { ExtractMetadataInput } from \"@webiny/api-file-manager/features/extractMetadata/ExtractMetadataInput.js\";\n\nclass ExtractMetadataTaskImpl implements TaskDefinition.Interface<ExtractMetadataInput> {\n public readonly id = \"fileManagerExtractMetadata\";\n public readonly title = \"Extract image metadata (dimensions, EXIF, IPTC)\";\n public readonly description = \"A task to extract metadata from uploaded image files\";\n public readonly maxIterations = 1;\n public readonly isPrivate = true;\n public readonly databaseLogs = false;\n public readonly selfCleanup = [\"onSuccess\" as const, \"onAbort\" as const];\n\n public constructor(\n private readonly metadataReader: MetadataReader.Interface,\n private readonly 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 from the key-value store. */\n const fileMetadata = await this.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 /* Only process image files. */\n if (!fileMetadata.contentType.startsWith(\"image/\")) {\n return controller.response.done();\n }\n\n const storagePath =
|
|
1
|
+
{"version":3,"file":"features/ExtractMetadata/ExtractMetadataTask.js","sources":["../../../src/features/ExtractMetadata/ExtractMetadataTask.ts"],"sourcesContent":["import { promises as fs } from \"node:fs\";\nimport type { ExifTags } from \"exifreader\";\nimport { TaskDefinition } from \"@webiny/api-core/features/task/TaskDefinition/index.js\";\nimport { UpdateFileUseCase } from \"@webiny/api-file-manager/features/file/UpdateFile/index.js\";\nimport { MetadataReader } from \"@webiny/api-file-manager/features/upload/ReadFileMetadata/abstractions.js\";\nimport type { ExtractMetadataInput } from \"@webiny/api-file-manager/features/extractMetadata/ExtractMetadataInput.js\";\nimport { FileManagerServerConfig } from \"~/features/FileManagerServerConfig/abstractions.js\";\n\nclass ExtractMetadataTaskImpl implements TaskDefinition.Interface<ExtractMetadataInput> {\n public readonly id = \"fileManagerExtractMetadata\";\n public readonly title = \"Extract image metadata (dimensions, EXIF, IPTC)\";\n public readonly description = \"A task to extract metadata from uploaded image files\";\n public readonly maxIterations = 1;\n public readonly isPrivate = true;\n public readonly databaseLogs = false;\n public readonly selfCleanup = [\"onSuccess\" as const, \"onAbort\" as const];\n\n public constructor(\n private readonly metadataReader: MetadataReader.Interface,\n private readonly updateFileUseCase: UpdateFileUseCase.Interface,\n private readonly config: FileManagerServerConfig.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 from the key-value store. */\n const fileMetadata = await this.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 /* Only process image files. */\n if (!fileMetadata.contentType.startsWith(\"image/\")) {\n return controller.response.done();\n }\n\n const storagePath = this.config.storagePath;\n const filePath = `${storagePath}/${fileMetadata.bucketKey}`;\n\n try {\n /* Read the image file from local disk. */\n const buffer = await fs.readFile(filePath);\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 /* Extract image dimensions using Sharp. */\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, unknown> = {\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, unknown> = {};\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: ExtractMetadataTaskImpl,\n dependencies: [MetadataReader, UpdateFileUseCase, FileManagerServerConfig]\n});\n"],"names":["ExtractMetadataTaskImpl","metadataReader","updateFileUseCase","config","input","controller","fileMetadata","storagePath","filePath","buffer","fs","sharp","m","ExifReader","sharpInstance","sharpMetadata","tags","metadata","updateResult","error","Error","String","cleaned","key","tag","Object","undefined","Array","ExtractMetadataTaskDefinition","TaskDefinition","MetadataReader","UpdateFileUseCase","FileManagerServerConfig"],"mappings":";;;;;AAQA,MAAMA;IASF,YACqBC,cAAwC,EACxCC,iBAA8C,EAC9CC,MAAyC,CAC5D;aAHmBF,cAAc,GAAdA;aACAC,iBAAiB,GAAjBA;aACAC,MAAM,GAANA;aAXL,EAAE,GAAG;aACL,KAAK,GAAG;aACR,WAAW,GAAG;aACd,aAAa,GAAG;aAChB,SAAS,GAAG;aACZ,YAAY,GAAG;aACf,WAAW,GAAG;YAAC;YAAsB;SAAmB;IAMrE;IAEH,MAAa,IAAI,EACbC,KAAK,EACLC,UAAU,EACmC,EAE/C;QACE,IAAIA,WAAW,OAAO,CAAC,SAAS,IAC5B,OAAOA,WAAW,QAAQ,CAAC,OAAO;QAItC,MAAMC,eAAe,MAAM,IAAI,CAAC,cAAc,CAAC,IAAI,CAACF,MAAM,MAAM;QAEhE,IAAI,CAACE,cACD,OAAOD,WAAW,QAAQ,CAAC,KAAK,CAAC;YAC7B,SAAS,CAAC,qCAAqC,EAAED,MAAM,MAAM,EAAE;QACnE;QAIJ,IAAI,CAACE,aAAa,WAAW,CAAC,UAAU,CAAC,WACrC,OAAOD,WAAW,QAAQ,CAAC,IAAI;QAGnC,MAAME,cAAc,IAAI,CAAC,MAAM,CAAC,WAAW;QAC3C,MAAMC,WAAW,GAAGD,YAAY,CAAC,EAAED,aAAa,SAAS,EAAE;QAE3D,IAAI;YAEA,MAAMG,SAAS,MAAMC,SAAAA,QAAW,CAACF;YAEjC,MAAMG,QAAQ,MAAM,MAAM,CAAiC,SAAS,IAAI,CACpEC,CAAAA,IAAKA,EAAE,OAAO;YAGlB,MAAMC,aAAa,MAAM,MAAM,CAAsC,cAAc,IAAI,CACnFD,CAAAA,IAAKA,EAAE,OAAO;YAIlB,MAAME,gBAAgBH,MAAMF;YAC5B,MAAMM,gBAAgB,MAAMD,cAAc,QAAQ;YAGlD,MAAME,OAAOH,WAAW,IAAI,CAACJ,QAAQ;gBAAE,UAAU;YAAK;YAGtD,MAAMQ,WAAoC;gBACtC,OAAO;oBACH,OAAOF,cAAc,KAAK;oBAC1B,QAAQA,cAAc,MAAM;oBAC5B,QAAQA,cAAc,MAAM;oBAC5B,aAAaA,cAAc,WAAW,IAAI;gBAC9C;YACJ;YAGA,IAAIC,KAAK,IAAI,EACTC,SAAS,IAAI,GAAG,IAAI,CAAC,WAAW,CAACD,KAAK,IAAI;YAI9C,IAAIA,KAAK,IAAI,EACTC,SAAS,IAAI,GAAG,IAAI,CAAC,WAAW,CAACD,KAAK,IAAI;YAI9C,MAAME,eAAe,MAAM,IAAI,CAAC,iBAAiB,CAAC,OAAO,CAAC;gBACtD,IAAId,MAAM,MAAM;gBAChBa;YACJ;YAEA,IAAIC,aAAa,MAAM,IACnB,OAAOb,WAAW,QAAQ,CAAC,KAAK,CAAC;gBAC7B,SAAS,CAAC,qCAAqC,EAAEa,aAAa,KAAK,CAAC,OAAO,EAAE;YACjF;YAGJ,OAAOb,WAAW,QAAQ,CAAC,IAAI;QACnC,EAAE,OAAOc,OAAO;YACZ,OAAOd,WAAW,QAAQ,CAAC,KAAK,CAAC;gBAC7B,SAAS,CAAC,4BAA4B,EAClCc,iBAAiBC,QAAQD,MAAM,OAAO,GAAGE,OAAOF,QAClD;YACN;QACJ;IACJ;IAEQ,YAAYH,IAAc,EAAE;QAChC,MAAMM,UAAmC,CAAC;QAE1C,KAAK,MAAM,CAACC,KAAKC,IAAI,IAAIC,OAAO,OAAO,CAACT,MACpC,IAAI,AAACQ,OAAO,AAAe,YAAf,OAAOA,KAKnB;YAAA,IAAIA,AAAoBE,WAApBF,IAAI,WAAW,IAAkBA,AAAoB,SAApBA,IAAI,WAAW,EAChDF,OAAO,CAACC,IAAI,GAAGC,IAAI,WAAW;iBAC3B,IAAIG,MAAM,OAAO,CAACH,IAAI,KAAK,KAAKA,IAAI,KAAK,CAAC,MAAM,GAAG;iBAEnD,IAAIA,AAAcE,WAAdF,IAAI,KAAK,EAChBF,OAAO,CAACC,IAAI,GAAGC,IAAI,KAAK;QAC5B;QAGJ,OAAOF;IACX;AACJ;AAEO,MAAMM,gCAAgCC,eAAe,oBAAoB,CAAC;IAC7E,gBAAgB7B;IAChB,cAAc;QAAC8B;QAAgBC;QAAmBC;KAAwB;AAC9E"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { BuildParams } from "@webiny/api-core/features/buildParams/index.js";
|
|
2
|
+
import { FileManagerServerConfig as FileManagerServerConfigAbstraction } from "./abstractions.js";
|
|
3
|
+
declare class FileManagerServerConfigImpl implements FileManagerServerConfigAbstraction.Interface {
|
|
4
|
+
readonly storagePath: string;
|
|
5
|
+
readonly uploadSecret: string;
|
|
6
|
+
readonly apiUrl: string;
|
|
7
|
+
constructor(buildParams: BuildParams.Interface);
|
|
8
|
+
}
|
|
9
|
+
export declare const FileManagerServerConfig: typeof FileManagerServerConfigImpl & {
|
|
10
|
+
__abstraction: import("@webiny/di").Abstraction<import("./abstractions.js").IFileManagerServerConfig>;
|
|
11
|
+
};
|
|
12
|
+
export {};
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { existsSync, mkdirSync } from "node:fs";
|
|
2
|
+
import { BuildParams } from "@webiny/api-core/features/buildParams/index.js";
|
|
3
|
+
import { FileManagerServerConfig } from "./abstractions.js";
|
|
4
|
+
class FileManagerServerConfigImpl {
|
|
5
|
+
constructor(buildParams){
|
|
6
|
+
const storagePath = buildParams.get("WEBINY_LOCAL_STORAGE_PATH");
|
|
7
|
+
if (!storagePath) throw new Error('"WEBINY_LOCAL_STORAGE_PATH" build parameter is not defined. Please set it to a valid local path.');
|
|
8
|
+
const uploadSecret = buildParams.get("WEBINY_UPLOAD_SECRET");
|
|
9
|
+
if (!uploadSecret) throw new Error('"WEBINY_UPLOAD_SECRET" build parameter is not defined. Please set it to a secret string used to sign upload tokens.');
|
|
10
|
+
const apiUrl = buildParams.get("WEBINY_API_URL");
|
|
11
|
+
if (!apiUrl) throw new Error('"WEBINY_API_URL" build parameter is not defined. Configure it via <Infra.ApiUrl url="..." /> in webiny.config.');
|
|
12
|
+
this.storagePath = storagePath;
|
|
13
|
+
this.uploadSecret = uploadSecret;
|
|
14
|
+
this.apiUrl = apiUrl.replace(/\/+$/, "");
|
|
15
|
+
if (!existsSync(this.storagePath)) mkdirSync(this.storagePath, {
|
|
16
|
+
recursive: true
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
const FileManagerServerConfig_FileManagerServerConfig = FileManagerServerConfig.createImplementation({
|
|
21
|
+
implementation: FileManagerServerConfigImpl,
|
|
22
|
+
dependencies: [
|
|
23
|
+
BuildParams
|
|
24
|
+
]
|
|
25
|
+
});
|
|
26
|
+
export { FileManagerServerConfig_FileManagerServerConfig as FileManagerServerConfig };
|
|
27
|
+
|
|
28
|
+
//# sourceMappingURL=FileManagerServerConfig.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"features/FileManagerServerConfig/FileManagerServerConfig.js","sources":["../../../src/features/FileManagerServerConfig/FileManagerServerConfig.ts"],"sourcesContent":["import { existsSync, mkdirSync } from \"node:fs\";\nimport { BuildParams } from \"@webiny/api-core/features/buildParams/index.js\";\nimport { FileManagerServerConfig as FileManagerServerConfigAbstraction } from \"./abstractions.js\";\n\nclass FileManagerServerConfigImpl implements FileManagerServerConfigAbstraction.Interface {\n public readonly storagePath: string;\n public readonly uploadSecret: string;\n public readonly apiUrl: string;\n\n constructor(buildParams: BuildParams.Interface) {\n const storagePath = buildParams.get<string>(\"WEBINY_LOCAL_STORAGE_PATH\");\n if (!storagePath) {\n throw new Error(\n `\"WEBINY_LOCAL_STORAGE_PATH\" build parameter is not defined. Please set it to a valid local path.`\n );\n }\n\n const uploadSecret = buildParams.get<string>(\"WEBINY_UPLOAD_SECRET\");\n if (!uploadSecret) {\n throw new Error(\n `\"WEBINY_UPLOAD_SECRET\" build parameter is not defined. Please set it to a secret string used to sign upload tokens.`\n );\n }\n\n // The API's own public origin, used to build client-reachable URLs (upload endpoint + file\n // srcPrefix). A build param (baked by Infra.ApiUrl), NOT a process.env read in api runtime code.\n const apiUrl = buildParams.get<string>(\"WEBINY_API_URL\");\n if (!apiUrl) {\n throw new Error(\n `\"WEBINY_API_URL\" build parameter is not defined. Configure it via <Infra.ApiUrl url=\"...\" /> in webiny.config.`\n );\n }\n\n this.storagePath = storagePath;\n this.uploadSecret = uploadSecret;\n this.apiUrl = apiUrl.replace(/\\/+$/, \"\");\n\n // Ensure the storage directory exists. Done here (on first resolve, at request time) rather\n // than in FileManagerServerFeature.register(): build params like WEBINY_LOCAL_STORAGE_PATH are\n // only registered once project extensions are applied, which happens LATER in the request\n // stack than the file-manager transport hook — so resolving this config at register() time\n // would read the param before it exists and throw.\n if (!existsSync(this.storagePath)) {\n mkdirSync(this.storagePath, { recursive: true });\n }\n }\n}\n\nexport const FileManagerServerConfig = FileManagerServerConfigAbstraction.createImplementation({\n implementation: FileManagerServerConfigImpl,\n dependencies: [BuildParams]\n});\n"],"names":["FileManagerServerConfigImpl","buildParams","storagePath","Error","uploadSecret","apiUrl","existsSync","mkdirSync","FileManagerServerConfig","FileManagerServerConfigAbstraction","BuildParams"],"mappings":";;;AAIA,MAAMA;IAKF,YAAYC,WAAkC,CAAE;QAC5C,MAAMC,cAAcD,YAAY,GAAG,CAAS;QAC5C,IAAI,CAACC,aACD,MAAM,IAAIC,MACN;QAIR,MAAMC,eAAeH,YAAY,GAAG,CAAS;QAC7C,IAAI,CAACG,cACD,MAAM,IAAID,MACN;QAMR,MAAME,SAASJ,YAAY,GAAG,CAAS;QACvC,IAAI,CAACI,QACD,MAAM,IAAIF,MACN;QAIR,IAAI,CAAC,WAAW,GAAGD;QACnB,IAAI,CAAC,YAAY,GAAGE;QACpB,IAAI,CAAC,MAAM,GAAGC,OAAO,OAAO,CAAC,QAAQ;QAOrC,IAAI,CAACC,WAAW,IAAI,CAAC,WAAW,GAC5BC,UAAU,IAAI,CAAC,WAAW,EAAE;YAAE,WAAW;QAAK;IAEtD;AACJ;AAEO,MAAMC,kDAA0BC,wBAAAA,oBAAuD,CAAC;IAC3F,gBAAgBT;IAChB,cAAc;QAACU;KAAY;AAC/B"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export interface IFileManagerServerConfig {
|
|
2
|
+
readonly storagePath: string;
|
|
3
|
+
readonly uploadSecret: string;
|
|
4
|
+
/** The API's public origin (no trailing slash), e.g. https://api.example.com. */
|
|
5
|
+
readonly apiUrl: string;
|
|
6
|
+
}
|
|
7
|
+
export declare const FileManagerServerConfig: import("@webiny/di").Abstraction<IFileManagerServerConfig>;
|
|
8
|
+
export declare namespace FileManagerServerConfig {
|
|
9
|
+
type Interface = IFileManagerServerConfig;
|
|
10
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"features/FileManagerServerConfig/abstractions.js","sources":["../../../src/features/FileManagerServerConfig/abstractions.ts"],"sourcesContent":["import { createAbstraction } from \"@webiny/feature/api\";\n\nexport interface IFileManagerServerConfig {\n readonly storagePath: string;\n readonly uploadSecret: string;\n /** The API's public origin (no trailing slash), e.g. https://api.example.com. */\n readonly apiUrl: string;\n}\n\nexport const FileManagerServerConfig = createAbstraction<IFileManagerServerConfig>(\n \"FileManagerServer/Config\"\n);\n\nexport namespace FileManagerServerConfig {\n export type Interface = IFileManagerServerConfig;\n}\n"],"names":["FileManagerServerConfig","createAbstraction"],"mappings":";AASO,MAAMA,0BAA0BC,kBACnC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { createFeature } from "@webiny/feature/api";
|
|
2
|
+
import { FileManagerServerConfig } from "./FileManagerServerConfig.js";
|
|
3
|
+
const FileManagerServerConfigFeature = createFeature({
|
|
4
|
+
name: "FileManagerServer/Config",
|
|
5
|
+
register (container) {
|
|
6
|
+
container.register(FileManagerServerConfig);
|
|
7
|
+
}
|
|
8
|
+
});
|
|
9
|
+
export { FileManagerServerConfigFeature };
|
|
10
|
+
|
|
11
|
+
//# sourceMappingURL=feature.js.map
|