@webiny/api-file-manager-server 0.0.0-unstable.0d717d18dd → 0.0.0-unstable.a4f3e4ea8b
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/assetDelivery/LocalAssetResolver.d.ts +4 -6
- package/assetDelivery/LocalAssetResolver.js +9 -9
- package/assetDelivery/LocalAssetResolver.js.map +1 -1
- package/assetDelivery/LocalOutputStrategy.d.ts +2 -3
- package/assetDelivery/LocalOutputStrategy.js +4 -4
- package/assetDelivery/LocalOutputStrategy.js.map +1 -1
- package/assetDelivery/LocalSharpTransform.d.ts +2 -2
- package/assetDelivery/LocalSharpTransform.js +34 -21
- package/assetDelivery/LocalSharpTransform.js.map +1 -1
- package/assetDelivery/assetDeliveryConfig.d.ts +1 -1
- package/assetDelivery/feature.js +6 -11
- package/assetDelivery/feature.js.map +1 -1
- package/features/CleanupStaleMultipartUploads/CleanupStaleMultipartUploadsTask.d.ts +0 -3
- package/features/CleanupStaleMultipartUploads/CleanupStaleMultipartUploadsTask.js +14 -18
- package/features/CleanupStaleMultipartUploads/CleanupStaleMultipartUploadsTask.js.map +1 -1
- package/features/CompleteMultiPartUpload/CompleteMultiPartUploadUseCase.d.ts +5 -7
- package/features/CompleteMultiPartUpload/CompleteMultiPartUploadUseCase.js +5 -8
- 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 +10 -9
- 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 +1 -3
- package/features/DeleteFileFromDisk/DeleteFileFromDiskHandler.js +3 -6
- package/features/DeleteFileFromDisk/DeleteFileFromDiskHandler.js.map +1 -1
- package/features/ExtractMetadata/ExtractMetadataTask.d.ts +1 -3
- package/features/ExtractMetadata/ExtractMetadataTask.js +3 -6
- package/features/ExtractMetadata/ExtractMetadataTask.js.map +1 -1
- package/features/GetFileContentsById/GetFileContentsByIdUseCase.d.ts +5 -7
- package/features/GetFileContentsById/GetFileContentsByIdUseCase.js +5 -8
- 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 +5 -7
- package/features/GetFileContentsByKey/GetFileContentsByKeyUseCase.js +5 -8
- 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 +9 -8
- package/features/GetUploadPayload/GetUploadPayloadUseCase.js.map +1 -1
- package/features/GetUploadPayload/feature.js +2 -2
- package/features/GetUploadPayload/feature.js.map +1 -1
- package/index.d.ts +2 -1
- package/index.js +40 -1
- package/index.js.map +1 -0
- package/package.json +13 -13
- package/routes/uploadRoutes.d.ts +4 -0
- package/routes/uploadRoutes.js +130 -0
- package/routes/uploadRoutes.js.map +1 -0
- package/utils/resolveServerUrl.d.ts +2 -0
- package/utils/resolveServerUrl.js +10 -0
- package/utils/resolveServerUrl.js.map +1 -0
- package/FileManagerServerFeature.d.ts +0 -5
- package/FileManagerServerFeature.js +0 -41
- package/FileManagerServerFeature.js.map +0 -1
- package/features/FileManagerServerConfig/FileManagerServerConfig.d.ts +0 -12
- package/features/FileManagerServerConfig/FileManagerServerConfig.js +0 -28
- package/features/FileManagerServerConfig/FileManagerServerConfig.js.map +0 -1
- package/features/FileManagerServerConfig/abstractions.d.ts +0 -10
- package/features/FileManagerServerConfig/abstractions.js +0 -5
- package/features/FileManagerServerConfig/abstractions.js.map +0 -1
- package/features/FileManagerServerConfig/feature.d.ts +0 -4
- package/features/FileManagerServerConfig/feature.js +0 -11
- package/features/FileManagerServerConfig/feature.js.map +0 -1
- package/graphql/ServerGraphQLSchema.d.ts +0 -15
- package/graphql/ServerGraphQLSchema.js +0 -221
- package/graphql/ServerGraphQLSchema.js.map +0 -1
- package/routes/UploadPartRoute/UploadPartRoute.d.ts +0 -14
- package/routes/UploadPartRoute/UploadPartRoute.js +0 -66
- package/routes/UploadPartRoute/UploadPartRoute.js.map +0 -1
- package/routes/UploadPartRoute/feature.d.ts +0 -4
- package/routes/UploadPartRoute/feature.js +0 -11
- package/routes/UploadPartRoute/feature.js.map +0 -1
- package/routes/UploadSingleFileRoute/UploadSingleFileRoute.d.ts +0 -14
- package/routes/UploadSingleFileRoute/UploadSingleFileRoute.js +0 -70
- package/routes/UploadSingleFileRoute/UploadSingleFileRoute.js.map +0 -1
- package/routes/UploadSingleFileRoute/feature.d.ts +0 -4
- package/routes/UploadSingleFileRoute/feature.js +0 -11
- package/routes/UploadSingleFileRoute/feature.js.map +0 -1
- package/routes/utils.d.ts +0 -20
- package/routes/utils.js +0 -62
- package/routes/utils.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"features/GetUploadPayload/GetUploadPayloadUseCase.js","sources":["../../../src/features/GetUploadPayload/GetUploadPayloadUseCase.ts"],"sourcesContent":["import { validation } from \"@webiny/validation\";\nimport { TenantContext } from \"@webiny/api-core/features/tenancy/TenantContext/index.js\";\nimport {
|
|
1
|
+
{"version":3,"file":"features/GetUploadPayload/GetUploadPayloadUseCase.js","sources":["../../../src/features/GetUploadPayload/GetUploadPayloadUseCase.ts"],"sourcesContent":["import { validation } from \"@webiny/validation\";\nimport { TenantContext } from \"@webiny/api-core/features/tenancy/TenantContext/index.js\";\nimport { Request } from \"@webiny/handler/abstractions/Request.js\";\nimport { GetUploadPayloadUseCase } from \"@webiny/api-file-manager/features/upload/GetUploadPayload/index.js\";\nimport type { FileData } from \"@webiny/api-file-manager/features/upload/types.js\";\nimport type { UploadPayloadResponse } from \"@webiny/api-file-manager/features/upload/types.js\";\nimport type { FileManagerSettings } from \"@webiny/api-file-manager/domain/settings/types.js\";\nimport { createUploadToken } from \"~/utils/uploadToken.js\";\nimport { resolveServerUrl } from \"~/utils/resolveServerUrl.js\";\n\nconst UPLOAD_MAX_FILE_SIZE_DEFAULT = 1099511627776; /* 1TB */\n\nconst sanitizeFileSizeValue = (value: number, defaultValue: number): number => {\n try {\n validation.validateSync(value, \"required,numeric,gte:0\");\n return value;\n } catch {\n return defaultValue;\n }\n};\n\nclass GetUploadPayloadUseCaseImpl implements GetUploadPayloadUseCase.Interface {\n public constructor(\n private readonly tenantContext: TenantContext.Interface,\n private readonly request: Request.Interface\n ) {}\n\n public async execute(\n file: FileData,\n settings: FileManagerSettings\n ): Promise<UploadPayloadResponse> {\n const uploadMinFileSize = sanitizeFileSizeValue(settings.uploadMinFileSize, 0);\n const uploadMaxFileSize = sanitizeFileSizeValue(\n settings.uploadMaxFileSize,\n UPLOAD_MAX_FILE_SIZE_DEFAULT\n );\n\n const tenant = this.tenantContext.getTenant();\n const storageKey = `tenants/${tenant.id}/files/${file.key}`;\n const secret = process.env.WEBINY_UPLOAD_SECRET as string;\n const expiresAt = Date.now() + 60_000;\n\n const token = createUploadToken(\n {\n key: storageKey,\n tenantId: tenant.id,\n expiresAt,\n uploadMinFileSize,\n uploadMaxFileSize\n },\n secret\n );\n\n const serverUrl = await resolveServerUrl(this.request);\n\n const data = {\n url: `${serverUrl}/webiny-file-upload`,\n fields: {\n key: storageKey,\n token\n }\n };\n\n return {\n data: data as unknown as Record<string, unknown>,\n file\n };\n }\n}\n\nexport const GetUploadPayloadUseCaseImplementation = GetUploadPayloadUseCase.createImplementation({\n implementation: GetUploadPayloadUseCaseImpl,\n dependencies: [TenantContext, Request]\n});\n"],"names":["UPLOAD_MAX_FILE_SIZE_DEFAULT","sanitizeFileSizeValue","value","defaultValue","validation","GetUploadPayloadUseCaseImpl","tenantContext","request","file","settings","uploadMinFileSize","uploadMaxFileSize","tenant","storageKey","secret","process","expiresAt","Date","token","createUploadToken","serverUrl","resolveServerUrl","data","GetUploadPayloadUseCaseImplementation","GetUploadPayloadUseCase","TenantContext","Request"],"mappings":";;;;;;AAUA,MAAMA,+BAA+B;AAErC,MAAMC,wBAAwB,CAACC,OAAeC;IAC1C,IAAI;QACAC,WAAW,YAAY,CAACF,OAAO;QAC/B,OAAOA;IACX,EAAE,OAAM;QACJ,OAAOC;IACX;AACJ;AAEA,MAAME;IACF,YACqBC,aAAsC,EACtCC,OAA0B,CAC7C;aAFmBD,aAAa,GAAbA;aACAC,OAAO,GAAPA;IAClB;IAEH,MAAa,QACTC,IAAc,EACdC,QAA6B,EACC;QAC9B,MAAMC,oBAAoBT,sBAAsBQ,SAAS,iBAAiB,EAAE;QAC5E,MAAME,oBAAoBV,sBACtBQ,SAAS,iBAAiB,EAC1BT;QAGJ,MAAMY,SAAS,IAAI,CAAC,aAAa,CAAC,SAAS;QAC3C,MAAMC,aAAa,CAAC,QAAQ,EAAED,OAAO,EAAE,CAAC,OAAO,EAAEJ,KAAK,GAAG,EAAE;QAC3D,MAAMM,SAASC,QAAQ,GAAG,CAAC,oBAAoB;QAC/C,MAAMC,YAAYC,KAAK,GAAG,KAAK;QAE/B,MAAMC,QAAQC,kBACV;YACI,KAAKN;YACL,UAAUD,OAAO,EAAE;YACnBI;YACAN;YACAC;QACJ,GACAG;QAGJ,MAAMM,YAAY,MAAMC,iBAAiB,IAAI,CAAC,OAAO;QAErD,MAAMC,OAAO;YACT,KAAK,GAAGF,UAAU,mBAAmB,CAAC;YACtC,QAAQ;gBACJ,KAAKP;gBACLK;YACJ;QACJ;QAEA,OAAO;YACH,MAAMI;YACNd;QACJ;IACJ;AACJ;AAEO,MAAMe,wCAAwCC,wBAAwB,oBAAoB,CAAC;IAC9F,gBAAgBnB;IAChB,cAAc;QAACoB;QAAeC;KAAQ;AAC1C"}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { createFeature } from "@webiny/feature/api";
|
|
2
|
-
import {
|
|
2
|
+
import { GetUploadPayloadUseCaseImplementation } from "./GetUploadPayloadUseCase.js";
|
|
3
3
|
const GetUploadPayloadFeature = createFeature({
|
|
4
4
|
name: "FileManagerServer/GetUploadPayload",
|
|
5
5
|
register (container) {
|
|
6
|
-
container.register(
|
|
6
|
+
container.register(GetUploadPayloadUseCaseImplementation);
|
|
7
7
|
}
|
|
8
8
|
});
|
|
9
9
|
export { GetUploadPayloadFeature };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"features/GetUploadPayload/feature.js","sources":["../../../src/features/GetUploadPayload/feature.ts"],"sourcesContent":["import { createFeature } from \"@webiny/feature/api\";\nimport {
|
|
1
|
+
{"version":3,"file":"features/GetUploadPayload/feature.js","sources":["../../../src/features/GetUploadPayload/feature.ts"],"sourcesContent":["import { createFeature } from \"@webiny/feature/api\";\nimport { GetUploadPayloadUseCaseImplementation } from \"./GetUploadPayloadUseCase.js\";\n\nexport const GetUploadPayloadFeature = createFeature({\n name: \"FileManagerServer/GetUploadPayload\",\n register(container) {\n container.register(GetUploadPayloadUseCaseImplementation);\n }\n});\n"],"names":["GetUploadPayloadFeature","createFeature","container","GetUploadPayloadUseCaseImplementation"],"mappings":";;AAGO,MAAMA,0BAA0BC,cAAc;IACjD,MAAM;IACN,UAASC,SAAS;QACdA,UAAU,QAAQ,CAACC;IACvB;AACJ"}
|
package/index.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { ContextPlugin } from "@webiny/api";
|
|
1
2
|
export { createFileUploadModifier } from "@webiny/api-file-manager/features/upload/index.js";
|
|
2
3
|
export { createAssetDelivery } from "./assetDelivery/createAssetDelivery.js";
|
|
3
|
-
export
|
|
4
|
+
export declare const createFileManagerServer: () => (ContextPlugin<import("@webiny/api/types.js").Context> | import("@webiny/handler/index.js").ModifyFastifyPlugin | import("@webiny/handler/index.js").RoutePlugin<import("@webiny/handler/types.js").Context>)[];
|
package/index.js
CHANGED
|
@@ -1,3 +1,42 @@
|
|
|
1
|
+
import { existsSync, mkdirSync } from "node:fs";
|
|
2
|
+
import { ContextPlugin } from "@webiny/api";
|
|
3
|
+
import { modifyFastifyPlugin, uploadRoutesPlugin } from "./routes/uploadRoutes.js";
|
|
4
|
+
import { CleanupStaleMultipartUploadsFeature } from "./features/CleanupStaleMultipartUploads/feature.js";
|
|
5
|
+
import { DeleteFileFromDiskFeature } from "./features/DeleteFileFromDisk/feature.js";
|
|
6
|
+
import { ExtractMetadataFeature } from "./features/ExtractMetadata/feature.js";
|
|
7
|
+
import { FlushCacheFeature } from "./features/FlushCache/feature.js";
|
|
8
|
+
import { GetFileContentsByIdFeature } from "./features/GetFileContentsById/feature.js";
|
|
9
|
+
import { GetFileContentsByKeyFeature } from "./features/GetFileContentsByKey/feature.js";
|
|
10
|
+
import { GetUploadPayloadFeature } from "./features/GetUploadPayload/feature.js";
|
|
11
|
+
import { CreateMultiPartUploadFeature } from "./features/CreateMultiPartUpload/feature.js";
|
|
12
|
+
import { CompleteMultiPartUploadFeature } from "./features/CompleteMultiPartUpload/feature.js";
|
|
13
|
+
const contextPlugin = new ContextPlugin((context)=>{
|
|
14
|
+
const storagePath = process.env["WEBINY_LOCAL_STORAGE_PATH"];
|
|
15
|
+
if (!storagePath) throw new Error('"WEBINY_LOCAL_STORAGE_PATH" environment variable is not defined. Please set it to a valid local path.');
|
|
16
|
+
const uploadSecret = process.env["WEBINY_UPLOAD_SECRET"];
|
|
17
|
+
if (!uploadSecret) throw new Error('"WEBINY_UPLOAD_SECRET" environment variable is not defined. Please set it to a secret string used to sign upload tokens.');
|
|
18
|
+
if (!existsSync(storagePath)) mkdirSync(storagePath, {
|
|
19
|
+
recursive: true
|
|
20
|
+
});
|
|
21
|
+
const container = context.container;
|
|
22
|
+
FlushCacheFeature.register(container);
|
|
23
|
+
DeleteFileFromDiskFeature.register(container);
|
|
24
|
+
ExtractMetadataFeature.register(container);
|
|
25
|
+
GetFileContentsByIdFeature.register(container);
|
|
26
|
+
GetFileContentsByKeyFeature.register(container);
|
|
27
|
+
GetUploadPayloadFeature.register(container);
|
|
28
|
+
CreateMultiPartUploadFeature.register(container);
|
|
29
|
+
CompleteMultiPartUploadFeature.register(container);
|
|
30
|
+
CleanupStaleMultipartUploadsFeature.register(container);
|
|
31
|
+
});
|
|
32
|
+
contextPlugin.name = "fileManagerServer.context";
|
|
33
|
+
const createFileManagerServer = ()=>[
|
|
34
|
+
contextPlugin,
|
|
35
|
+
uploadRoutesPlugin,
|
|
36
|
+
modifyFastifyPlugin
|
|
37
|
+
];
|
|
1
38
|
export { createFileUploadModifier } from "@webiny/api-file-manager/features/upload/index.js";
|
|
2
39
|
export { createAssetDelivery } from "./assetDelivery/createAssetDelivery.js";
|
|
3
|
-
export {
|
|
40
|
+
export { createFileManagerServer };
|
|
41
|
+
|
|
42
|
+
//# sourceMappingURL=index.js.map
|
package/index.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../src/index.ts"],"sourcesContent":["import { existsSync } from \"node:fs\";\nimport { mkdirSync } from \"node:fs\";\nimport { ContextPlugin } from \"@webiny/api\";\nimport { uploadRoutesPlugin } from \"~/routes/uploadRoutes.js\";\nimport { modifyFastifyPlugin } from \"~/routes/uploadRoutes.js\";\nimport { CleanupStaleMultipartUploadsFeature } from \"~/features/CleanupStaleMultipartUploads/feature.js\";\nimport { DeleteFileFromDiskFeature } from \"~/features/DeleteFileFromDisk/feature.js\";\nimport { ExtractMetadataFeature } from \"~/features/ExtractMetadata/feature.js\";\nimport { FlushCacheFeature } from \"~/features/FlushCache/feature.js\";\nimport { GetFileContentsByIdFeature } from \"~/features/GetFileContentsById/feature.js\";\nimport { GetFileContentsByKeyFeature } from \"~/features/GetFileContentsByKey/feature.js\";\nimport { GetUploadPayloadFeature } from \"~/features/GetUploadPayload/feature.js\";\nimport { CreateMultiPartUploadFeature } from \"~/features/CreateMultiPartUpload/feature.js\";\nimport { CompleteMultiPartUploadFeature } from \"~/features/CompleteMultiPartUpload/feature.js\";\nexport { createFileUploadModifier } from \"@webiny/api-file-manager/features/upload/index.js\";\nexport { createAssetDelivery } from \"./assetDelivery/createAssetDelivery.js\";\n\nconst contextPlugin = new ContextPlugin(context => {\n const storagePath = process.env[\"WEBINY_LOCAL_STORAGE_PATH\"];\n if (!storagePath) {\n throw new Error(\n `\"WEBINY_LOCAL_STORAGE_PATH\" environment variable is not defined. Please set it to a valid local path.`\n );\n }\n\n const uploadSecret = process.env[\"WEBINY_UPLOAD_SECRET\"];\n if (!uploadSecret) {\n throw new Error(\n `\"WEBINY_UPLOAD_SECRET\" environment variable is not defined. Please set it to a secret string used to sign upload tokens.`\n );\n }\n\n if (!existsSync(storagePath)) {\n mkdirSync(storagePath, { recursive: true });\n }\n\n const container = context.container;\n\n FlushCacheFeature.register(container);\n DeleteFileFromDiskFeature.register(container);\n ExtractMetadataFeature.register(container);\n GetFileContentsByIdFeature.register(container);\n GetFileContentsByKeyFeature.register(container);\n GetUploadPayloadFeature.register(container);\n CreateMultiPartUploadFeature.register(container);\n CompleteMultiPartUploadFeature.register(container);\n CleanupStaleMultipartUploadsFeature.register(container);\n});\n\ncontextPlugin.name = `fileManagerServer.context`;\n\nexport const createFileManagerServer = () => [\n contextPlugin,\n uploadRoutesPlugin,\n modifyFastifyPlugin\n];\n"],"names":["contextPlugin","ContextPlugin","context","storagePath","process","Error","uploadSecret","existsSync","mkdirSync","container","FlushCacheFeature","DeleteFileFromDiskFeature","ExtractMetadataFeature","GetFileContentsByIdFeature","GetFileContentsByKeyFeature","GetUploadPayloadFeature","CreateMultiPartUploadFeature","CompleteMultiPartUploadFeature","CleanupStaleMultipartUploadsFeature","createFileManagerServer","uploadRoutesPlugin","modifyFastifyPlugin"],"mappings":";;;;;;;;;;;;AAiBA,MAAMA,gBAAgB,IAAIC,cAAcC,CAAAA;IACpC,MAAMC,cAAcC,QAAQ,GAAG,CAAC,4BAA4B;IAC5D,IAAI,CAACD,aACD,MAAM,IAAIE,MACN;IAIR,MAAMC,eAAeF,QAAQ,GAAG,CAAC,uBAAuB;IACxD,IAAI,CAACE,cACD,MAAM,IAAID,MACN;IAIR,IAAI,CAACE,WAAWJ,cACZK,UAAUL,aAAa;QAAE,WAAW;IAAK;IAG7C,MAAMM,YAAYP,QAAQ,SAAS;IAEnCQ,kBAAkB,QAAQ,CAACD;IAC3BE,0BAA0B,QAAQ,CAACF;IACnCG,uBAAuB,QAAQ,CAACH;IAChCI,2BAA2B,QAAQ,CAACJ;IACpCK,4BAA4B,QAAQ,CAACL;IACrCM,wBAAwB,QAAQ,CAACN;IACjCO,6BAA6B,QAAQ,CAACP;IACtCQ,+BAA+B,QAAQ,CAACR;IACxCS,oCAAoC,QAAQ,CAACT;AACjD;AAEAT,cAAc,IAAI,GAAG;AAEd,MAAMmB,0BAA0B,IAAM;QACzCnB;QACAoB;QACAC;KACH"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@webiny/api-file-manager-server",
|
|
3
|
-
"version": "0.0.0-unstable.
|
|
3
|
+
"version": "0.0.0-unstable.a4f3e4ea8b",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"exports": {
|
|
6
6
|
".": "./index.js",
|
|
@@ -14,22 +14,22 @@
|
|
|
14
14
|
"author": "Webiny Ltd",
|
|
15
15
|
"license": "MIT",
|
|
16
16
|
"dependencies": {
|
|
17
|
-
"@
|
|
18
|
-
"@webiny/api
|
|
19
|
-
"@webiny/api-
|
|
20
|
-
"@webiny/
|
|
21
|
-
"@webiny/
|
|
22
|
-
"@webiny/feature": "0.0.0-unstable.
|
|
23
|
-
"@webiny/handler": "0.0.0-unstable.
|
|
24
|
-
"@webiny/plugins": "0.0.0-unstable.
|
|
25
|
-
"@webiny/utils": "0.0.0-unstable.
|
|
26
|
-
"@webiny/validation": "0.0.0-unstable.
|
|
17
|
+
"@fastify/multipart": "10.1.0",
|
|
18
|
+
"@webiny/api": "0.0.0-unstable.a4f3e4ea8b",
|
|
19
|
+
"@webiny/api-core": "0.0.0-unstable.a4f3e4ea8b",
|
|
20
|
+
"@webiny/api-file-manager": "0.0.0-unstable.a4f3e4ea8b",
|
|
21
|
+
"@webiny/background-tasks": "0.0.0-unstable.a4f3e4ea8b",
|
|
22
|
+
"@webiny/feature": "0.0.0-unstable.a4f3e4ea8b",
|
|
23
|
+
"@webiny/handler": "0.0.0-unstable.a4f3e4ea8b",
|
|
24
|
+
"@webiny/plugins": "0.0.0-unstable.a4f3e4ea8b",
|
|
25
|
+
"@webiny/utils": "0.0.0-unstable.a4f3e4ea8b",
|
|
26
|
+
"@webiny/validation": "0.0.0-unstable.a4f3e4ea8b",
|
|
27
27
|
"exifreader": "4.41.3",
|
|
28
|
-
"
|
|
28
|
+
"fastify": "5.10.0",
|
|
29
29
|
"sharp": "0.35.3"
|
|
30
30
|
},
|
|
31
31
|
"devDependencies": {
|
|
32
|
-
"@webiny/build-tools": "0.0.0-unstable.
|
|
32
|
+
"@webiny/build-tools": "0.0.0-unstable.a4f3e4ea8b",
|
|
33
33
|
"rimraf": "6.1.3",
|
|
34
34
|
"typescript": "7.0.2",
|
|
35
35
|
"vitest": "4.1.10"
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { RoutePlugin } from "@webiny/handler/plugins/RoutePlugin.js";
|
|
2
|
+
import { ModifyFastifyPlugin } from "@webiny/handler/plugins/ModifyFastifyPlugin.js";
|
|
3
|
+
export declare const modifyFastifyPlugin: ModifyFastifyPlugin;
|
|
4
|
+
export declare const uploadRoutesPlugin: RoutePlugin<import("@webiny/handler/types").Context>;
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import node_path from "node:path";
|
|
2
|
+
import { Readable } from "node:stream";
|
|
3
|
+
import { createHash } from "node:crypto";
|
|
4
|
+
import { mkdir, writeFile } from "node:fs/promises";
|
|
5
|
+
import { createWriteStream } from "node:fs";
|
|
6
|
+
import { pipeline } from "node:stream/promises";
|
|
7
|
+
import { RoutePlugin } from "@webiny/handler/plugins/RoutePlugin.js";
|
|
8
|
+
import { ModifyFastifyPlugin } from "@webiny/handler/plugins/ModifyFastifyPlugin.js";
|
|
9
|
+
import { verifyUploadToken } from "../utils/uploadToken.js";
|
|
10
|
+
const getStoragePath = ()=>String(process.env.WEBINY_LOCAL_STORAGE_PATH);
|
|
11
|
+
const getUploadSecret = ()=>String(process.env.WEBINY_UPLOAD_SECRET);
|
|
12
|
+
const isPathContained = (filePath, storagePath)=>{
|
|
13
|
+
const resolved = node_path.resolve(filePath);
|
|
14
|
+
const root = node_path.resolve(storagePath);
|
|
15
|
+
if (!resolved.startsWith(root + node_path.sep) && resolved !== root) return false;
|
|
16
|
+
return true;
|
|
17
|
+
};
|
|
18
|
+
const modifyFastifyPlugin = new ModifyFastifyPlugin((app)=>{
|
|
19
|
+
app.register(import("@fastify/multipart"), {
|
|
20
|
+
limits: {
|
|
21
|
+
fileSize: 5368709120
|
|
22
|
+
}
|
|
23
|
+
});
|
|
24
|
+
app.addContentTypeParser("application/octet-stream", {
|
|
25
|
+
parseAs: "buffer"
|
|
26
|
+
}, (_request, body, done)=>{
|
|
27
|
+
done(null, body);
|
|
28
|
+
});
|
|
29
|
+
});
|
|
30
|
+
modifyFastifyPlugin.name = "fileManagerServer.modifyFastify";
|
|
31
|
+
const uploadRoutesPlugin = new RoutePlugin(({ onPost, onPut })=>{
|
|
32
|
+
onPost("/webiny-file-upload", async (request, reply)=>{
|
|
33
|
+
const storagePath = getStoragePath();
|
|
34
|
+
const secret = getUploadSecret();
|
|
35
|
+
let key;
|
|
36
|
+
let token;
|
|
37
|
+
let fileChunks;
|
|
38
|
+
let fileSize = 0;
|
|
39
|
+
const parts = request.parts();
|
|
40
|
+
for await (const part of parts)if ("field" === part.type) {
|
|
41
|
+
if ("key" === part.fieldname) key = part.value;
|
|
42
|
+
else if ("token" === part.fieldname) token = part.value;
|
|
43
|
+
} else if ("file" === part.type) {
|
|
44
|
+
const chunks = [];
|
|
45
|
+
for await (const chunk of part.file){
|
|
46
|
+
chunks.push(chunk);
|
|
47
|
+
fileSize += chunk.length;
|
|
48
|
+
}
|
|
49
|
+
fileChunks = chunks;
|
|
50
|
+
}
|
|
51
|
+
if (!key || !token) return reply.code(400).send({
|
|
52
|
+
error: "Missing key or token."
|
|
53
|
+
});
|
|
54
|
+
if (!fileChunks) return reply.code(400).send({
|
|
55
|
+
error: "No file in request."
|
|
56
|
+
});
|
|
57
|
+
let payload;
|
|
58
|
+
try {
|
|
59
|
+
payload = verifyUploadToken(token, secret);
|
|
60
|
+
} catch (err) {
|
|
61
|
+
return reply.code(400).send({
|
|
62
|
+
error: err instanceof Error ? err.message : "Invalid token."
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
if (payload.key !== key) return reply.code(400).send({
|
|
66
|
+
error: "Token key mismatch."
|
|
67
|
+
});
|
|
68
|
+
if (payload.uploadMaxFileSize > 0 && fileSize > payload.uploadMaxFileSize) return reply.code(400).send({
|
|
69
|
+
error: "File exceeds maximum allowed size."
|
|
70
|
+
});
|
|
71
|
+
if (payload.uploadMinFileSize > 0 && fileSize < payload.uploadMinFileSize) return reply.code(400).send({
|
|
72
|
+
error: "File is below minimum allowed size."
|
|
73
|
+
});
|
|
74
|
+
const destPath = node_path.join(storagePath, key);
|
|
75
|
+
if (!isPathContained(destPath, storagePath)) return reply.code(400).send({
|
|
76
|
+
error: "Invalid path."
|
|
77
|
+
});
|
|
78
|
+
const destDir = node_path.dirname(destPath);
|
|
79
|
+
await mkdir(destDir, {
|
|
80
|
+
recursive: true
|
|
81
|
+
});
|
|
82
|
+
const writeStream = createWriteStream(destPath);
|
|
83
|
+
const readable = Readable.from(fileChunks);
|
|
84
|
+
await pipeline(readable, writeStream);
|
|
85
|
+
return reply.code(204).send();
|
|
86
|
+
});
|
|
87
|
+
onPut("/webiny-file-upload/parts", async (request, reply)=>{
|
|
88
|
+
const storagePath = getStoragePath();
|
|
89
|
+
const secret = getUploadSecret();
|
|
90
|
+
const query = request.query;
|
|
91
|
+
const uploadId = query["uploadId"];
|
|
92
|
+
const partNumberStr = query["partNumber"];
|
|
93
|
+
const token = query["token"];
|
|
94
|
+
if (!uploadId || !partNumberStr || !token) return reply.code(400).send({
|
|
95
|
+
error: "Missing uploadId, partNumber, or token."
|
|
96
|
+
});
|
|
97
|
+
const partNumber = parseInt(partNumberStr, 10);
|
|
98
|
+
if (isNaN(partNumber) || partNumber < 1) return reply.code(400).send({
|
|
99
|
+
error: "Invalid partNumber."
|
|
100
|
+
});
|
|
101
|
+
let payload;
|
|
102
|
+
try {
|
|
103
|
+
payload = verifyUploadToken(token, secret);
|
|
104
|
+
} catch (err) {
|
|
105
|
+
return reply.code(400).send({
|
|
106
|
+
error: err instanceof Error ? err.message : "Invalid token."
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
const expectedKey = `tenants/${payload.tenantId}/multipart/${uploadId}/part-${partNumber}`;
|
|
110
|
+
if (payload.key !== expectedKey) return reply.code(400).send({
|
|
111
|
+
error: "Token key mismatch."
|
|
112
|
+
});
|
|
113
|
+
const destPath = node_path.join(storagePath, expectedKey);
|
|
114
|
+
if (!isPathContained(destPath, storagePath)) return reply.code(400).send({
|
|
115
|
+
error: "Invalid path."
|
|
116
|
+
});
|
|
117
|
+
const destDir = node_path.dirname(destPath);
|
|
118
|
+
await mkdir(destDir, {
|
|
119
|
+
recursive: true
|
|
120
|
+
});
|
|
121
|
+
const body = request.body;
|
|
122
|
+
await writeFile(destPath, body);
|
|
123
|
+
const etag = createHash("md5").update(body).digest("hex");
|
|
124
|
+
return reply.code(200).header("ETag", etag).send();
|
|
125
|
+
});
|
|
126
|
+
});
|
|
127
|
+
uploadRoutesPlugin.name = "fileManagerServer.uploadRoutes";
|
|
128
|
+
export { modifyFastifyPlugin, uploadRoutesPlugin };
|
|
129
|
+
|
|
130
|
+
//# sourceMappingURL=uploadRoutes.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"routes/uploadRoutes.js","sources":["../../src/routes/uploadRoutes.ts"],"sourcesContent":["import path from \"node:path\";\nimport { Readable } from \"node:stream\";\nimport { createHash } from \"node:crypto\";\nimport { mkdir } from \"node:fs/promises\";\nimport { writeFile } from \"node:fs/promises\";\nimport { createWriteStream } from \"node:fs\";\nimport { pipeline } from \"node:stream/promises\";\nimport { RoutePlugin } from \"@webiny/handler/plugins/RoutePlugin.js\";\nimport { ModifyFastifyPlugin } from \"@webiny/handler/plugins/ModifyFastifyPlugin.js\";\nimport { verifyUploadToken } from \"~/utils/uploadToken.js\";\n\nconst getStoragePath = (): string => {\n return String(process.env.WEBINY_LOCAL_STORAGE_PATH);\n};\n\nconst getUploadSecret = (): string => {\n return String(process.env.WEBINY_UPLOAD_SECRET);\n};\n\nconst isPathContained = (filePath: string, storagePath: string): boolean => {\n const resolved = path.resolve(filePath);\n const root = path.resolve(storagePath);\n if (!resolved.startsWith(root + path.sep) && resolved !== root) {\n return false;\n }\n return true;\n};\n\nexport const modifyFastifyPlugin = new ModifyFastifyPlugin(app => {\n app.register(import(\"@fastify/multipart\"), {\n limits: {\n fileSize: 5 * 1024 * 1024 * 1024 /* 5 GB */\n }\n });\n\n app.addContentTypeParser(\n \"application/octet-stream\",\n { parseAs: \"buffer\" },\n (_request, body, done) => {\n done(null, body);\n }\n );\n});\n\nmodifyFastifyPlugin.name = \"fileManagerServer.modifyFastify\";\n\nexport const uploadRoutesPlugin = new RoutePlugin(({ onPost, onPut }) => {\n /* POST /webiny-file-upload — simple single-file upload via multipart/form-data.\n Form fields: key (storage path), token (HMAC upload token).\n File field: the raw file bytes (any field name). */\n onPost(\"/webiny-file-upload\", async (request, reply) => {\n const storagePath = getStoragePath();\n const secret = getUploadSecret();\n\n let key: string | undefined;\n let token: string | undefined;\n let fileChunks: Buffer[] | undefined;\n let fileSize = 0;\n\n const parts = request.parts();\n\n for await (const part of parts) {\n if (part.type === \"field\") {\n if (part.fieldname === \"key\") {\n key = part.value as string;\n } else if (part.fieldname === \"token\") {\n token = part.value as string;\n }\n } else if (part.type === \"file\") {\n /* Collect the file stream into memory so we can measure and hash it. */\n const chunks: Buffer[] = [];\n for await (const chunk of part.file) {\n chunks.push(chunk as Buffer);\n fileSize += (chunk as Buffer).length;\n }\n fileChunks = chunks;\n }\n }\n\n if (!key || !token) {\n return reply.code(400).send({ error: \"Missing key or token.\" });\n }\n\n if (!fileChunks) {\n return reply.code(400).send({ error: \"No file in request.\" });\n }\n\n let payload;\n try {\n payload = verifyUploadToken(token, secret);\n } catch (err) {\n return reply\n .code(400)\n .send({ error: err instanceof Error ? err.message : \"Invalid token.\" });\n }\n\n if (payload.key !== key) {\n return reply.code(400).send({ error: \"Token key mismatch.\" });\n }\n\n if (payload.uploadMaxFileSize > 0 && fileSize > payload.uploadMaxFileSize) {\n return reply.code(400).send({ error: \"File exceeds maximum allowed size.\" });\n }\n\n if (payload.uploadMinFileSize > 0 && fileSize < payload.uploadMinFileSize) {\n return reply.code(400).send({ error: \"File is below minimum allowed size.\" });\n }\n\n const destPath = path.join(storagePath, key);\n\n if (!isPathContained(destPath, storagePath)) {\n return reply.code(400).send({ error: \"Invalid path.\" });\n }\n\n const destDir = path.dirname(destPath);\n await mkdir(destDir, { recursive: true });\n\n const writeStream = createWriteStream(destPath);\n const readable = Readable.from(fileChunks);\n\n await pipeline(readable, writeStream);\n\n return reply.code(204).send();\n });\n\n /* PUT /webiny-file-upload/parts — multipart chunk upload via raw binary body.\n Query params: uploadId, partNumber, token.\n Body: raw binary chunk (application/octet-stream). */\n onPut(\"/webiny-file-upload/parts\", async (request, reply) => {\n const storagePath = getStoragePath();\n const secret = getUploadSecret();\n\n const query = request.query as Record<string, string | undefined>;\n const uploadId = query[\"uploadId\"];\n const partNumberStr = query[\"partNumber\"];\n const token = query[\"token\"];\n\n if (!uploadId || !partNumberStr || !token) {\n return reply.code(400).send({ error: \"Missing uploadId, partNumber, or token.\" });\n }\n\n const partNumber = parseInt(partNumberStr, 10);\n if (isNaN(partNumber) || partNumber < 1) {\n return reply.code(400).send({ error: \"Invalid partNumber.\" });\n }\n\n let payload;\n try {\n payload = verifyUploadToken(token, secret);\n } catch (err) {\n return reply\n .code(400)\n .send({ error: err instanceof Error ? err.message : \"Invalid token.\" });\n }\n\n const expectedKey = `tenants/${payload.tenantId}/multipart/${uploadId}/part-${partNumber}`;\n\n if (payload.key !== expectedKey) {\n return reply.code(400).send({ error: \"Token key mismatch.\" });\n }\n\n const destPath = path.join(storagePath, expectedKey);\n\n if (!isPathContained(destPath, storagePath)) {\n return reply.code(400).send({ error: \"Invalid path.\" });\n }\n\n const destDir = path.dirname(destPath);\n await mkdir(destDir, { recursive: true });\n\n const body = request.body as Buffer;\n\n await writeFile(destPath, body);\n\n const etag = createHash(\"md5\").update(body).digest(\"hex\");\n\n return reply.code(200).header(\"ETag\", etag).send();\n });\n});\n\nuploadRoutesPlugin.name = \"fileManagerServer.uploadRoutes\";\n"],"names":["getStoragePath","String","process","getUploadSecret","isPathContained","filePath","storagePath","resolved","path","root","modifyFastifyPlugin","ModifyFastifyPlugin","app","_request","body","done","uploadRoutesPlugin","RoutePlugin","onPost","onPut","request","reply","secret","key","token","fileChunks","fileSize","parts","part","chunks","chunk","payload","verifyUploadToken","err","Error","destPath","destDir","mkdir","writeStream","createWriteStream","readable","Readable","pipeline","query","uploadId","partNumberStr","partNumber","parseInt","isNaN","expectedKey","writeFile","etag","createHash"],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { ServiceDiscovery } from "@webiny/api-core/features/serviceDiscovery/ServiceDiscovery.js";
|
|
2
|
+
const resolveServerUrl = async (request)=>{
|
|
3
|
+
const manifest = await ServiceDiscovery.load();
|
|
4
|
+
const domain = manifest?.api?.cloudfront?.domain;
|
|
5
|
+
if (domain) return domain;
|
|
6
|
+
return `${request.protocol}://${request.hostname}`;
|
|
7
|
+
};
|
|
8
|
+
export { resolveServerUrl };
|
|
9
|
+
|
|
10
|
+
//# sourceMappingURL=resolveServerUrl.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils/resolveServerUrl.js","sources":["../../src/utils/resolveServerUrl.ts"],"sourcesContent":["import { ServiceDiscovery } from \"@webiny/api-core/features/serviceDiscovery/ServiceDiscovery.js\";\nimport type { FastifyRequest } from \"fastify\";\n\nexport const resolveServerUrl = async (request: FastifyRequest): Promise<string> => {\n const manifest = await ServiceDiscovery.load();\n const domain = manifest?.api?.cloudfront?.domain;\n if (domain) {\n return domain as string;\n }\n\n return `${request.protocol}://${request.hostname}`;\n};\n"],"names":["resolveServerUrl","request","manifest","ServiceDiscovery","domain"],"mappings":";AAGO,MAAMA,mBAAmB,OAAOC;IACnC,MAAMC,WAAW,MAAMC,iBAAiB,IAAI;IAC5C,MAAMC,SAASF,UAAU,KAAK,YAAY;IAC1C,IAAIE,QACA,OAAOA;IAGX,OAAO,GAAGH,QAAQ,QAAQ,CAAC,GAAG,EAAEA,QAAQ,QAAQ,EAAE;AACtD"}
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
import { createFeature } from "@webiny/feature/api";
|
|
2
|
-
import { ReadFileMetadataFeature } from "@webiny/api-file-manager/features/upload/ReadFileMetadata/feature.js";
|
|
3
|
-
import { WriteFileMetadataFeature } from "@webiny/api-file-manager/features/upload/WriteFileMetadata/feature.js";
|
|
4
|
-
import { createLocalAssetDeliveryFeature } from "./assetDelivery/feature.js";
|
|
5
|
-
import { ServerGraphQLSchema } from "./graphql/ServerGraphQLSchema.js";
|
|
6
|
-
import { FileManagerServerConfigFeature } from "./features/FileManagerServerConfig/feature.js";
|
|
7
|
-
import { UploadSingleFileRouteFeature } from "./routes/UploadSingleFileRoute/feature.js";
|
|
8
|
-
import { UploadPartRouteFeature } from "./routes/UploadPartRoute/feature.js";
|
|
9
|
-
import { CleanupStaleMultipartUploadsFeature } from "./features/CleanupStaleMultipartUploads/feature.js";
|
|
10
|
-
import { DeleteFileFromDiskFeature } from "./features/DeleteFileFromDisk/feature.js";
|
|
11
|
-
import { ExtractMetadataFeature } from "./features/ExtractMetadata/feature.js";
|
|
12
|
-
import { FlushCacheFeature } from "./features/FlushCache/feature.js";
|
|
13
|
-
import { GetFileContentsByIdFeature } from "./features/GetFileContentsById/feature.js";
|
|
14
|
-
import { GetFileContentsByKeyFeature } from "./features/GetFileContentsByKey/feature.js";
|
|
15
|
-
import { GetUploadPayloadFeature } from "./features/GetUploadPayload/feature.js";
|
|
16
|
-
import { CreateMultiPartUploadFeature } from "./features/CreateMultiPartUpload/feature.js";
|
|
17
|
-
import { CompleteMultiPartUploadFeature } from "./features/CompleteMultiPartUpload/feature.js";
|
|
18
|
-
const FileManagerServerFeature = createFeature({
|
|
19
|
-
name: "FileManagerServer",
|
|
20
|
-
register (container) {
|
|
21
|
-
FileManagerServerConfigFeature.register(container);
|
|
22
|
-
createLocalAssetDeliveryFeature().register(container);
|
|
23
|
-
ReadFileMetadataFeature.register(container);
|
|
24
|
-
WriteFileMetadataFeature.register(container);
|
|
25
|
-
FlushCacheFeature.register(container);
|
|
26
|
-
DeleteFileFromDiskFeature.register(container);
|
|
27
|
-
ExtractMetadataFeature.register(container);
|
|
28
|
-
GetFileContentsByIdFeature.register(container);
|
|
29
|
-
GetFileContentsByKeyFeature.register(container);
|
|
30
|
-
GetUploadPayloadFeature.register(container);
|
|
31
|
-
CreateMultiPartUploadFeature.register(container);
|
|
32
|
-
CompleteMultiPartUploadFeature.register(container);
|
|
33
|
-
CleanupStaleMultipartUploadsFeature.register(container);
|
|
34
|
-
UploadSingleFileRouteFeature.register(container);
|
|
35
|
-
UploadPartRouteFeature.register(container);
|
|
36
|
-
container.register(ServerGraphQLSchema);
|
|
37
|
-
}
|
|
38
|
-
});
|
|
39
|
-
export { FileManagerServerFeature };
|
|
40
|
-
|
|
41
|
-
//# sourceMappingURL=FileManagerServerFeature.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"FileManagerServerFeature.js","sources":["../src/FileManagerServerFeature.ts"],"sourcesContent":["import { type Container, createFeature } from \"@webiny/feature/api\";\nimport { ReadFileMetadataFeature } from \"@webiny/api-file-manager/features/upload/ReadFileMetadata/feature.js\";\nimport { WriteFileMetadataFeature } from \"@webiny/api-file-manager/features/upload/WriteFileMetadata/feature.js\";\nimport { createLocalAssetDeliveryFeature } from \"~/assetDelivery/feature.js\";\nimport { ServerGraphQLSchema } from \"~/graphql/ServerGraphQLSchema.js\";\nimport { FileManagerServerConfigFeature } from \"~/features/FileManagerServerConfig/feature.js\";\nimport { UploadSingleFileRouteFeature } from \"~/routes/UploadSingleFileRoute/feature.js\";\nimport { UploadPartRouteFeature } from \"~/routes/UploadPartRoute/feature.js\";\nimport { CleanupStaleMultipartUploadsFeature } from \"~/features/CleanupStaleMultipartUploads/feature.js\";\nimport { DeleteFileFromDiskFeature } from \"~/features/DeleteFileFromDisk/feature.js\";\nimport { ExtractMetadataFeature } from \"~/features/ExtractMetadata/feature.js\";\nimport { FlushCacheFeature } from \"~/features/FlushCache/feature.js\";\nimport { GetFileContentsByIdFeature } from \"~/features/GetFileContentsById/feature.js\";\nimport { GetFileContentsByKeyFeature } from \"~/features/GetFileContentsByKey/feature.js\";\nimport { GetUploadPayloadFeature } from \"~/features/GetUploadPayload/feature.js\";\nimport { CreateMultiPartUploadFeature } from \"~/features/CreateMultiPartUpload/feature.js\";\nimport { CompleteMultiPartUploadFeature } from \"~/features/CompleteMultiPartUpload/feature.js\";\n\nexport const FileManagerServerFeature = createFeature({\n name: \"FileManagerServer\",\n register(container: Container) {\n // NOTE: do NOT resolve FileManagerServerConfig here. This runs at the file-manager transport\n // hook, BEFORE project extensions (which register the WEBINY_LOCAL_STORAGE_PATH /\n // WEBINY_UPLOAD_SECRET build params) are applied later in the request stack. Config is resolved\n // lazily at request time by the routes/use-cases below; it also ensures its storage dir on\n // construction. Resolving it eagerly here would read the build params before they exist.\n FileManagerServerConfigFeature.register(container);\n\n // Local (disk) asset-delivery implementations (LocalAssetResolver/OutputStrategy/SharpTransform)\n // override the null delivery registered by AssetDeliveryFeature in FileManagerAppFeature — the\n // same seam FileManagerS3Feature uses with createS3AssetDeliveryFeature. Without this the domain\n // AssetDeliveryRoute resolves the null impls and serves nothing.\n createLocalAssetDeliveryFeature().register(container);\n\n // Metadata reader (FileManager/Upload/MetadataReader) — the generic domain impl backed by the\n // GlobalKeyValueStore. Required by the server's ExtractMetadata task + GetFileContentsById use\n // cases; without it createFile fails with \"No registration found for FileManager/Upload/MetadataReader\".\n ReadFileMetadataFeature.register(container);\n\n // Metadata writer — the generic domain WriteMetadataAfterCreate/BatchCreate event handlers write\n // the asset metadata (id/tenant/size/contentType/bucketKey) to the GlobalKeyValueStore on file\n // create. Asset delivery (LocalAssetResolver) reads that metadata to locate the file on disk;\n // without it every delivered file 404s (\"asset not found\"). Mirrors S3's WriteFileMetadataFeature.\n WriteFileMetadataFeature.register(container);\n\n FlushCacheFeature.register(container);\n DeleteFileFromDiskFeature.register(container);\n ExtractMetadataFeature.register(container);\n GetFileContentsByIdFeature.register(container);\n GetFileContentsByKeyFeature.register(container);\n GetUploadPayloadFeature.register(container);\n CreateMultiPartUploadFeature.register(container);\n CompleteMultiPartUploadFeature.register(container);\n CleanupStaleMultipartUploadsFeature.register(container);\n UploadSingleFileRouteFeature.register(container);\n UploadPartRouteFeature.register(container);\n\n // Upload GraphQL (getPreSignedPostPayload/getPreSignedPostPayloads + create/completeMultiPartUpload).\n // Mirrors how FileManagerS3Feature contributes its schema — same query/mutation names so the SDK\n // works unchanged; resolvers delegate to the server upload use cases registered above.\n container.register(ServerGraphQLSchema);\n }\n});\n"],"names":["FileManagerServerFeature","createFeature","container","FileManagerServerConfigFeature","createLocalAssetDeliveryFeature","ReadFileMetadataFeature","WriteFileMetadataFeature","FlushCacheFeature","DeleteFileFromDiskFeature","ExtractMetadataFeature","GetFileContentsByIdFeature","GetFileContentsByKeyFeature","GetUploadPayloadFeature","CreateMultiPartUploadFeature","CompleteMultiPartUploadFeature","CleanupStaleMultipartUploadsFeature","UploadSingleFileRouteFeature","UploadPartRouteFeature","ServerGraphQLSchema"],"mappings":";;;;;;;;;;;;;;;;;AAkBO,MAAMA,2BAA2BC,cAAc;IAClD,MAAM;IACN,UAASC,SAAoB;QAMzBC,+BAA+B,QAAQ,CAACD;QAMxCE,kCAAkC,QAAQ,CAACF;QAK3CG,wBAAwB,QAAQ,CAACH;QAMjCI,yBAAyB,QAAQ,CAACJ;QAElCK,kBAAkB,QAAQ,CAACL;QAC3BM,0BAA0B,QAAQ,CAACN;QACnCO,uBAAuB,QAAQ,CAACP;QAChCQ,2BAA2B,QAAQ,CAACR;QACpCS,4BAA4B,QAAQ,CAACT;QACrCU,wBAAwB,QAAQ,CAACV;QACjCW,6BAA6B,QAAQ,CAACX;QACtCY,+BAA+B,QAAQ,CAACZ;QACxCa,oCAAoC,QAAQ,CAACb;QAC7Cc,6BAA6B,QAAQ,CAACd;QACtCe,uBAAuB,QAAQ,CAACf;QAKhCA,UAAU,QAAQ,CAACgB;IACvB;AACJ"}
|
|
@@ -1,12 +0,0 @@
|
|
|
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 {};
|
|
@@ -1,28 +0,0 @@
|
|
|
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
|
|
@@ -1 +0,0 @@
|
|
|
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"}
|
|
@@ -1,10 +0,0 @@
|
|
|
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
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
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"}
|
|
@@ -1,11 +0,0 @@
|
|
|
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
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"features/FileManagerServerConfig/feature.js","sources":["../../../src/features/FileManagerServerConfig/feature.ts"],"sourcesContent":["import { createFeature } from \"@webiny/feature/api\";\nimport { FileManagerServerConfig } from \"./FileManagerServerConfig.js\";\n\nexport const FileManagerServerConfigFeature = createFeature({\n name: \"FileManagerServer/Config\",\n register(container) {\n container.register(FileManagerServerConfig);\n }\n});\n"],"names":["FileManagerServerConfigFeature","createFeature","container","FileManagerServerConfig"],"mappings":";;AAGO,MAAMA,iCAAiCC,cAAc;IACxD,MAAM;IACN,UAASC,SAAS;QACdA,UAAU,QAAQ,CAACC;IACvB;AACJ"}
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import { CoreGraphQLSchemaFactory } from "@webiny/api-graphql/graphql/abstractions.js";
|
|
2
|
-
import { GraphQLSchemaBuilder } from "@webiny/api-graphql/features/GraphQLSchemaBuilder/abstractions.js";
|
|
3
|
-
/**
|
|
4
|
-
* Upload GraphQL for the self-hosted (server) hosting type. Mirrors the SDL that `api-file-manager-s3`'s
|
|
5
|
-
* `S3GraphQLSchema` contributes (same query/mutation names + `PreSignedPostPayloadInput`), so the
|
|
6
|
-
* transport-agnostic SDK works unchanged. Only the resolvers differ from S3 — they resolve the server
|
|
7
|
-
* upload use cases (local disk + the `/webiny-file-upload` HTTP routes) instead of an S3 client.
|
|
8
|
-
*/
|
|
9
|
-
declare class ServerGraphQLSchemaImpl implements CoreGraphQLSchemaFactory.Interface {
|
|
10
|
-
execute(builder: GraphQLSchemaBuilder.Interface): CoreGraphQLSchemaFactory.Return;
|
|
11
|
-
}
|
|
12
|
-
export declare const ServerGraphQLSchema: typeof ServerGraphQLSchemaImpl & {
|
|
13
|
-
__abstraction: import("@webiny/di").Abstraction<import("@webiny/api-graphql/graphql/abstractions.core").ICoreGraphQLSchemaFactory>;
|
|
14
|
-
};
|
|
15
|
-
export {};
|