@webiny/api-file-manager-s3 5.35.2-beta.0 → 5.36.0-beta.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.
@@ -0,0 +1,13 @@
1
+ import S3 from "aws-sdk/clients/s3";
2
+ interface CompleteMultiPartUploadParams {
3
+ fileKey: string;
4
+ uploadId: string;
5
+ }
6
+ export declare class CompleteMultiPartUploadUseCase {
7
+ private readonly s3;
8
+ private readonly bucket;
9
+ constructor(bucket: string, s3Client: S3);
10
+ execute(params: CompleteMultiPartUploadParams): Promise<void>;
11
+ private getAllUploadParts;
12
+ }
13
+ export {};
@@ -0,0 +1,65 @@
1
+ "use strict";
2
+
3
+ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault").default;
4
+ Object.defineProperty(exports, "__esModule", {
5
+ value: true
6
+ });
7
+ exports.CompleteMultiPartUploadUseCase = void 0;
8
+ var _objectSpread2 = _interopRequireDefault(require("@babel/runtime/helpers/objectSpread2"));
9
+ var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
10
+ class CompleteMultiPartUploadUseCase {
11
+ constructor(bucket, s3Client) {
12
+ (0, _defineProperty2.default)(this, "s3", void 0);
13
+ (0, _defineProperty2.default)(this, "bucket", void 0);
14
+ this.bucket = bucket;
15
+ this.s3 = s3Client;
16
+ }
17
+ async execute(params) {
18
+ const uploadParams = {
19
+ Bucket: this.bucket,
20
+ Key: params.fileKey,
21
+ UploadId: params.uploadId
22
+ };
23
+ const allParts = await this.getAllUploadParts(uploadParams);
24
+ const s3Params = (0, _objectSpread2.default)((0, _objectSpread2.default)({}, uploadParams), {}, {
25
+ MultipartUpload: {
26
+ Parts: allParts
27
+ }
28
+ });
29
+ return new Promise((resolve, reject) => {
30
+ this.s3.completeMultipartUpload(s3Params, (err, data) => {
31
+ if (err) {
32
+ console.error(err);
33
+ reject(err);
34
+ return;
35
+ }
36
+ console.log(data);
37
+ resolve();
38
+ });
39
+ });
40
+ }
41
+ async getAllUploadParts(params) {
42
+ const parts = [];
43
+ let marker = undefined;
44
+ while (true) {
45
+ const {
46
+ Parts,
47
+ PartNumberMarker
48
+ } = await this.s3.listParts((0, _objectSpread2.default)((0, _objectSpread2.default)({}, params), {}, {
49
+ PartNumberMarker: marker
50
+ })).promise();
51
+ if (Parts) {
52
+ Parts.forEach(part => parts.push(part));
53
+ }
54
+ marker = PartNumberMarker || undefined;
55
+ if (!marker) {
56
+ break;
57
+ }
58
+ }
59
+ return parts.map(part => ({
60
+ ETag: part.ETag,
61
+ PartNumber: part.PartNumber
62
+ }));
63
+ }
64
+ }
65
+ exports.CompleteMultiPartUploadUseCase = CompleteMultiPartUploadUseCase;
@@ -0,0 +1 @@
1
+ {"version":3,"names":["CompleteMultiPartUploadUseCase","constructor","bucket","s3Client","s3","execute","params","uploadParams","Bucket","Key","fileKey","UploadId","uploadId","allParts","getAllUploadParts","s3Params","MultipartUpload","Parts","Promise","resolve","reject","completeMultipartUpload","err","data","console","error","log","parts","marker","undefined","PartNumberMarker","listParts","promise","forEach","part","push","map","ETag","PartNumber"],"sources":["CompleteMultiPartUploadUseCase.ts"],"sourcesContent":["import S3 from \"aws-sdk/clients/s3\";\n\ninterface CompleteMultiPartUploadParams {\n fileKey: string;\n uploadId: string;\n}\n\ninterface GetAllUploadPartsParams {\n Bucket: string;\n Key: string;\n UploadId: string;\n}\n\nexport class CompleteMultiPartUploadUseCase {\n private readonly s3: S3;\n private readonly bucket: string;\n\n constructor(bucket: string, s3Client: S3) {\n this.bucket = bucket;\n this.s3 = s3Client;\n }\n\n async execute(params: CompleteMultiPartUploadParams) {\n const uploadParams = {\n Bucket: this.bucket,\n Key: params.fileKey,\n UploadId: params.uploadId\n };\n\n const allParts = await this.getAllUploadParts(uploadParams);\n\n const s3Params = {\n ...uploadParams,\n MultipartUpload: {\n Parts: allParts\n }\n };\n\n return new Promise<void>((resolve, reject) => {\n this.s3.completeMultipartUpload(s3Params, (err, data) => {\n if (err) {\n console.error(err);\n reject(err);\n return;\n }\n\n console.log(data);\n resolve();\n });\n });\n }\n\n private async getAllUploadParts(params: GetAllUploadPartsParams) {\n const parts: S3.Parts = [];\n\n let marker: number | undefined = undefined;\n while (true) {\n const { Parts, PartNumberMarker }: S3.ListPartsOutput = await this.s3\n .listParts({\n ...params,\n PartNumberMarker: marker\n })\n .promise();\n\n if (Parts) {\n Parts.forEach(part => parts.push(part));\n }\n\n marker = PartNumberMarker || undefined;\n if (!marker) {\n break;\n }\n }\n\n return parts.map(part => ({\n ETag: part.ETag as string,\n PartNumber: part.PartNumber as number\n }));\n }\n}\n"],"mappings":";;;;;;;;;AAaO,MAAMA,8BAA8B,CAAC;EAIxCC,WAAW,CAACC,MAAc,EAAEC,QAAY,EAAE;IAAA;IAAA;IACtC,IAAI,CAACD,MAAM,GAAGA,MAAM;IACpB,IAAI,CAACE,EAAE,GAAGD,QAAQ;EACtB;EAEA,MAAME,OAAO,CAACC,MAAqC,EAAE;IACjD,MAAMC,YAAY,GAAG;MACjBC,MAAM,EAAE,IAAI,CAACN,MAAM;MACnBO,GAAG,EAAEH,MAAM,CAACI,OAAO;MACnBC,QAAQ,EAAEL,MAAM,CAACM;IACrB,CAAC;IAED,MAAMC,QAAQ,GAAG,MAAM,IAAI,CAACC,iBAAiB,CAACP,YAAY,CAAC;IAE3D,MAAMQ,QAAQ,+DACPR,YAAY;MACfS,eAAe,EAAE;QACbC,KAAK,EAAEJ;MACX;IAAC,EACJ;IAED,OAAO,IAAIK,OAAO,CAAO,CAACC,OAAO,EAAEC,MAAM,KAAK;MAC1C,IAAI,CAAChB,EAAE,CAACiB,uBAAuB,CAACN,QAAQ,EAAE,CAACO,GAAG,EAAEC,IAAI,KAAK;QACrD,IAAID,GAAG,EAAE;UACLE,OAAO,CAACC,KAAK,CAACH,GAAG,CAAC;UAClBF,MAAM,CAACE,GAAG,CAAC;UACX;QACJ;QAEAE,OAAO,CAACE,GAAG,CAACH,IAAI,CAAC;QACjBJ,OAAO,EAAE;MACb,CAAC,CAAC;IACN,CAAC,CAAC;EACN;EAEA,MAAcL,iBAAiB,CAACR,MAA+B,EAAE;IAC7D,MAAMqB,KAAe,GAAG,EAAE;IAE1B,IAAIC,MAA0B,GAAGC,SAAS;IAC1C,OAAO,IAAI,EAAE;MACT,MAAM;QAAEZ,KAAK;QAAEa;MAAqC,CAAC,GAAG,MAAM,IAAI,CAAC1B,EAAE,CAChE2B,SAAS,6DACHzB,MAAM;QACTwB,gBAAgB,EAAEF;MAAM,GAC1B,CACDI,OAAO,EAAE;MAEd,IAAIf,KAAK,EAAE;QACPA,KAAK,CAACgB,OAAO,CAACC,IAAI,IAAIP,KAAK,CAACQ,IAAI,CAACD,IAAI,CAAC,CAAC;MAC3C;MAEAN,MAAM,GAAGE,gBAAgB,IAAID,SAAS;MACtC,IAAI,CAACD,MAAM,EAAE;QACT;MACJ;IACJ;IAEA,OAAOD,KAAK,CAACS,GAAG,CAACF,IAAI,KAAK;MACtBG,IAAI,EAAEH,IAAI,CAACG,IAAc;MACzBC,UAAU,EAAEJ,IAAI,CAACI;IACrB,CAAC,CAAC,CAAC;EACP;AACJ;AAAC"}
@@ -0,0 +1,23 @@
1
+ import S3 from "aws-sdk/clients/s3";
2
+ interface CreateMultiPartUploadParams {
3
+ file: {
4
+ name: string;
5
+ type: string;
6
+ size: number;
7
+ };
8
+ numberOfParts: number;
9
+ }
10
+ export declare class CreateMultiPartUploadUseCase {
11
+ private readonly s3;
12
+ private readonly bucket;
13
+ constructor(bucket: string, s3Client: S3);
14
+ execute(params: CreateMultiPartUploadParams): Promise<{
15
+ file: import("../types").FileData;
16
+ uploadId: string | undefined;
17
+ parts: {
18
+ url: string;
19
+ partNumber: number;
20
+ }[];
21
+ }>;
22
+ }
23
+ export {};
@@ -0,0 +1,47 @@
1
+ "use strict";
2
+
3
+ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault").default;
4
+ Object.defineProperty(exports, "__esModule", {
5
+ value: true
6
+ });
7
+ exports.CreateMultiPartUploadUseCase = void 0;
8
+ var _objectSpread2 = _interopRequireDefault(require("@babel/runtime/helpers/objectSpread2"));
9
+ var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
10
+ var _prepareFileData = require("../utils/prepareFileData");
11
+ class CreateMultiPartUploadUseCase {
12
+ constructor(bucket, s3Client) {
13
+ (0, _defineProperty2.default)(this, "s3", void 0);
14
+ (0, _defineProperty2.default)(this, "bucket", void 0);
15
+ this.bucket = bucket;
16
+ this.s3 = s3Client;
17
+ }
18
+ async execute(params) {
19
+ const file = (0, _prepareFileData.prepareFileData)(params.file);
20
+ const s3Params = {
21
+ Bucket: this.bucket,
22
+ Key: file.key
23
+ };
24
+ const {
25
+ UploadId
26
+ } = await this.s3.createMultipartUpload(s3Params).promise();
27
+ const parts = await Promise.all(Array.from({
28
+ length: params.numberOfParts
29
+ }).map((_, index) => {
30
+ return this.s3.getSignedUrlPromise("uploadPart", (0, _objectSpread2.default)((0, _objectSpread2.default)({}, s3Params), {}, {
31
+ UploadId,
32
+ PartNumber: index + 1,
33
+ // URL expires after 24 hours.
34
+ Expires: 86400
35
+ })).then(url => ({
36
+ url,
37
+ partNumber: index + 1
38
+ }));
39
+ }));
40
+ return {
41
+ file,
42
+ uploadId: UploadId,
43
+ parts
44
+ };
45
+ }
46
+ }
47
+ exports.CreateMultiPartUploadUseCase = CreateMultiPartUploadUseCase;
@@ -0,0 +1 @@
1
+ {"version":3,"names":["CreateMultiPartUploadUseCase","constructor","bucket","s3Client","s3","execute","params","file","prepareFileData","s3Params","Bucket","Key","key","UploadId","createMultipartUpload","promise","parts","Promise","all","Array","from","length","numberOfParts","map","_","index","getSignedUrlPromise","PartNumber","Expires","then","url","partNumber","uploadId"],"sources":["CreateMultiPartUploadUseCase.ts"],"sourcesContent":["import S3 from \"aws-sdk/clients/s3\";\nimport { prepareFileData } from \"~/utils/prepareFileData\";\n\ninterface CreateMultiPartUploadParams {\n file: {\n name: string;\n type: string;\n size: number;\n };\n numberOfParts: number;\n}\n\nexport class CreateMultiPartUploadUseCase {\n private readonly s3: S3;\n private readonly bucket: string;\n\n constructor(bucket: string, s3Client: S3) {\n this.bucket = bucket;\n this.s3 = s3Client;\n }\n\n async execute(params: CreateMultiPartUploadParams) {\n const file = prepareFileData(params.file);\n\n const s3Params = { Bucket: this.bucket, Key: file.key };\n\n const { UploadId } = await this.s3.createMultipartUpload(s3Params).promise();\n\n const parts = await Promise.all(\n Array.from({ length: params.numberOfParts }).map((_, index) => {\n return this.s3\n .getSignedUrlPromise(\"uploadPart\", {\n ...s3Params,\n UploadId,\n PartNumber: index + 1,\n // URL expires after 24 hours.\n Expires: 86400\n })\n .then(url => ({\n url,\n partNumber: index + 1\n }));\n })\n );\n\n return {\n file,\n uploadId: UploadId,\n parts\n };\n }\n}\n"],"mappings":";;;;;;;;;AACA;AAWO,MAAMA,4BAA4B,CAAC;EAItCC,WAAW,CAACC,MAAc,EAAEC,QAAY,EAAE;IAAA;IAAA;IACtC,IAAI,CAACD,MAAM,GAAGA,MAAM;IACpB,IAAI,CAACE,EAAE,GAAGD,QAAQ;EACtB;EAEA,MAAME,OAAO,CAACC,MAAmC,EAAE;IAC/C,MAAMC,IAAI,GAAG,IAAAC,gCAAe,EAACF,MAAM,CAACC,IAAI,CAAC;IAEzC,MAAME,QAAQ,GAAG;MAAEC,MAAM,EAAE,IAAI,CAACR,MAAM;MAAES,GAAG,EAAEJ,IAAI,CAACK;IAAI,CAAC;IAEvD,MAAM;MAAEC;IAAS,CAAC,GAAG,MAAM,IAAI,CAACT,EAAE,CAACU,qBAAqB,CAACL,QAAQ,CAAC,CAACM,OAAO,EAAE;IAE5E,MAAMC,KAAK,GAAG,MAAMC,OAAO,CAACC,GAAG,CAC3BC,KAAK,CAACC,IAAI,CAAC;MAAEC,MAAM,EAAEf,MAAM,CAACgB;IAAc,CAAC,CAAC,CAACC,GAAG,CAAC,CAACC,CAAC,EAAEC,KAAK,KAAK;MAC3D,OAAO,IAAI,CAACrB,EAAE,CACTsB,mBAAmB,CAAC,YAAY,8DAC1BjB,QAAQ;QACXI,QAAQ;QACRc,UAAU,EAAEF,KAAK,GAAG,CAAC;QACrB;QACAG,OAAO,EAAE;MAAK,GAChB,CACDC,IAAI,CAACC,GAAG,KAAK;QACVA,GAAG;QACHC,UAAU,EAAEN,KAAK,GAAG;MACxB,CAAC,CAAC,CAAC;IACX,CAAC,CAAC,CACL;IAED,OAAO;MACHlB,IAAI;MACJyB,QAAQ,EAAEnB,QAAQ;MAClBG;IACJ,CAAC;EACL;AACJ;AAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@webiny/api-file-manager-s3",
3
- "version": "5.35.2-beta.0",
3
+ "version": "5.36.0-beta.0",
4
4
  "main": "index.js",
5
5
  "repository": {
6
6
  "type": "git",
@@ -10,13 +10,13 @@
10
10
  "author": "Webiny Ltd",
11
11
  "license": "MIT",
12
12
  "dependencies": {
13
- "@webiny/api-file-manager": "^5.35.2-beta.0",
14
- "@webiny/api-security": "^5.35.2-beta.0",
15
- "@webiny/error": "^5.35.2-beta.0",
16
- "@webiny/handler-graphql": "^5.35.2-beta.0",
17
- "@webiny/validation": "^5.35.2-beta.0",
13
+ "@webiny/api-file-manager": "5.36.0-beta.0",
14
+ "@webiny/api-security": "5.36.0-beta.0",
15
+ "@webiny/error": "5.36.0-beta.0",
16
+ "@webiny/handler-graphql": "5.36.0-beta.0",
17
+ "@webiny/utils": "5.36.0-beta.0",
18
+ "@webiny/validation": "5.36.0-beta.0",
18
19
  "form-data": "4.0.0",
19
- "mdbid": "1.0.0",
20
20
  "mime": "3.0.0",
21
21
  "node-fetch": "2.6.9",
22
22
  "sanitize-filename": "1.6.3"
@@ -25,8 +25,8 @@
25
25
  "@babel/cli": "7.20.7",
26
26
  "@babel/core": "7.20.12",
27
27
  "@types/node-fetch": "2.6.2",
28
- "@webiny/cli": "^5.35.2-beta.0",
29
- "@webiny/project-utils": "^5.35.2-beta.0",
28
+ "@webiny/cli": "5.36.0-beta.0",
29
+ "@webiny/project-utils": "5.36.0-beta.0",
30
30
  "rimraf": "3.0.2",
31
31
  "typescript": "4.7.4"
32
32
  },
@@ -38,5 +38,5 @@
38
38
  "build": "yarn webiny run build",
39
39
  "watch": "yarn webiny run watch"
40
40
  },
41
- "gitHead": "d3f7b134892b6c5ea794e9e7dd4811b27cdf6eb1"
41
+ "gitHead": "c59b9cc5b96b7fd91388de93c7fff2d977d25220"
42
42
  }
@@ -5,10 +5,13 @@ Object.defineProperty(exports, "__esModule", {
5
5
  value: true
6
6
  });
7
7
  exports.default = void 0;
8
+ var _s = _interopRequireDefault(require("aws-sdk/clients/s3"));
8
9
  var _responses = require("@webiny/handler-graphql/responses");
9
10
  var _getPresignedPostPayload = require("../utils/getPresignedPostPayload");
10
11
  var _error = _interopRequireDefault(require("@webiny/error"));
11
12
  var _checkPermission = require("./checkPermission");
13
+ var _CreateMultiPartUploadUseCase = require("../multiPartUpload/CreateMultiPartUploadUseCase");
14
+ var _CompleteMultiPartUploadUseCase = require("../multiPartUpload/CompleteMultiPartUploadUseCase");
12
15
  const plugin = {
13
16
  type: "graphql-schema",
14
17
  name: "graphql-schema-api-file-manager-s3",
@@ -39,6 +42,22 @@ const plugin = {
39
42
  data: GetPreSignedPostPayloadResponseData
40
43
  }
41
44
 
45
+ type MultiPartUploadFilePart {
46
+ partNumber: Int!
47
+ url: String!
48
+ }
49
+
50
+ type CreateMultiPartUploadResponseData {
51
+ file: GetPreSignedPostPayloadResponseDataFile!
52
+ uploadId: String!
53
+ parts: [MultiPartUploadFilePart!]!
54
+ }
55
+
56
+ type CompleteMultiPartUploadResponse {
57
+ data: Boolean
58
+ error: FileError
59
+ }
60
+
42
61
  type GetPreSignedPostPayloadsResponse {
43
62
  error: FileError
44
63
  data: [GetPreSignedPostPayloadResponseData!]!
@@ -52,6 +71,28 @@ const plugin = {
52
71
  data: [PreSignedPostPayloadInput]!
53
72
  ): GetPreSignedPostPayloadsResponse
54
73
  }
74
+
75
+ type CreateMultiPartUploadResponse {
76
+ data: CreateMultiPartUploadResponseData
77
+ error: FileError
78
+ }
79
+
80
+ input MultiPartUploadFilePartInput {
81
+ partNumber: Int!
82
+ etag: String!
83
+ }
84
+
85
+ extend type FmMutation {
86
+ createMultiPartUpload(
87
+ data: PreSignedPostPayloadInput!
88
+ numberOfParts: Number!
89
+ ): CreateMultiPartUploadResponse
90
+
91
+ completeMultiPartUpload(
92
+ fileKey: String!
93
+ uploadId: String!
94
+ ): CompleteMultiPartUploadResponse
95
+ }
55
96
  `,
56
97
  resolvers: {
57
98
  FmQuery: {
@@ -100,6 +141,54 @@ const plugin = {
100
141
  });
101
142
  }
102
143
  }
144
+ },
145
+ FmMutation: {
146
+ createMultiPartUpload: async (_, args, context) => {
147
+ await (0, _checkPermission.checkPermission)(context, {
148
+ rwd: "w"
149
+ });
150
+ const s3Client = new _s.default({
151
+ region: process.env.AWS_REGION,
152
+ signatureVersion: "v4"
153
+ });
154
+ try {
155
+ const useCase = new _CreateMultiPartUploadUseCase.CreateMultiPartUploadUseCase(String(process.env.S3_BUCKET), s3Client);
156
+ const multiPartUpload = await useCase.execute({
157
+ file: args.data,
158
+ numberOfParts: args.numberOfParts
159
+ });
160
+ return new _responses.Response(multiPartUpload);
161
+ } catch (e) {
162
+ return new _responses.ErrorResponse({
163
+ message: e.message,
164
+ code: e.code,
165
+ data: e.data
166
+ });
167
+ }
168
+ },
169
+ completeMultiPartUpload: async (_, args, context) => {
170
+ await (0, _checkPermission.checkPermission)(context, {
171
+ rwd: "w"
172
+ });
173
+ const s3Client = new _s.default({
174
+ region: process.env.AWS_REGION,
175
+ signatureVersion: "v4"
176
+ });
177
+ try {
178
+ const useCase = new _CompleteMultiPartUploadUseCase.CompleteMultiPartUploadUseCase(String(process.env.S3_BUCKET), s3Client);
179
+ await useCase.execute({
180
+ fileKey: args.fileKey,
181
+ uploadId: args.uploadId
182
+ });
183
+ return new _responses.Response(true);
184
+ } catch (e) {
185
+ return new _responses.ErrorResponse({
186
+ message: e.message,
187
+ code: e.code,
188
+ data: e.data
189
+ });
190
+ }
191
+ }
103
192
  }
104
193
  }
105
194
  }
@@ -1 +1 @@
1
- {"version":3,"names":["plugin","type","name","schema","typeDefs","resolvers","FmQuery","getPreSignedPostPayload","_","args","context","checkPermission","rwd","file","data","settings","fileManager","getSettings","WebinyError","Response","getPresignedPostPayload","e","ErrorResponse","message","code","getPreSignedPostPayloads","files","presignedPayloads","map"],"sources":["graphqlFileStorageS3.ts"],"sourcesContent":["import { GraphQLSchemaPlugin } from \"@webiny/handler-graphql/types\";\nimport { ErrorResponse, Response } from \"@webiny/handler-graphql/responses\";\nimport { FileManagerContext } from \"@webiny/api-file-manager/types\";\nimport { getPresignedPostPayload } from \"~/utils/getPresignedPostPayload\";\nimport WebinyError from \"@webiny/error\";\nimport { checkPermission } from \"~/plugins/checkPermission\";\nimport { PresignedPostPayloadData } from \"~/types\";\n\nconst plugin: GraphQLSchemaPlugin<FileManagerContext> = {\n type: \"graphql-schema\",\n name: \"graphql-schema-api-file-manager-s3\",\n schema: {\n typeDefs: /* GraphQL */ `\n input PreSignedPostPayloadInput {\n name: String!\n type: String!\n size: Long!\n }\n\n type GetPreSignedPostPayloadResponseDataFile {\n id: ID!\n name: String!\n type: String!\n size: Long!\n key: String!\n }\n\n type GetPreSignedPostPayloadResponseData {\n # Contains data that is necessary for initiating a file upload.\n data: JSON!\n file: UploadFileResponseDataFile!\n }\n\n type GetPreSignedPostPayloadResponse {\n error: FileError\n data: GetPreSignedPostPayloadResponseData\n }\n\n type GetPreSignedPostPayloadsResponse {\n error: FileError\n data: [GetPreSignedPostPayloadResponseData!]!\n }\n\n extend type FmQuery {\n getPreSignedPostPayload(\n data: PreSignedPostPayloadInput!\n ): GetPreSignedPostPayloadResponse\n getPreSignedPostPayloads(\n data: [PreSignedPostPayloadInput]!\n ): GetPreSignedPostPayloadsResponse\n }\n `,\n resolvers: {\n FmQuery: {\n getPreSignedPostPayload: async (_, args: any, context) => {\n try {\n await checkPermission(context, { rwd: \"w\" });\n\n const file = args.data as PresignedPostPayloadData;\n\n const settings = await context.fileManager.getSettings();\n if (!settings) {\n throw new WebinyError(\n \"Missing File Manager Settings.\",\n \"FILE_MANAGER_SETTINGS_ERROR\",\n { file }\n );\n }\n\n return new Response(getPresignedPostPayload(file, settings));\n } catch (e) {\n return new ErrorResponse({\n message: e.message,\n code: e.code,\n data: e.data\n });\n }\n },\n getPreSignedPostPayloads: async (_, args, context) => {\n await checkPermission(context, { rwd: \"w\" });\n\n const files = args.data as PresignedPostPayloadData[];\n\n try {\n const settings = await context.fileManager.getSettings();\n if (!settings) {\n throw new WebinyError(\n \"Missing File Manager Settings.\",\n \"FILE_MANAGER_SETTINGS_ERROR\",\n { files }\n );\n }\n\n const presignedPayloads = files.map(file => {\n return getPresignedPostPayload(file, settings);\n });\n\n return new Response(presignedPayloads);\n } catch (e) {\n return new ErrorResponse({\n message: e.message,\n code: e.code,\n data: e.data\n });\n }\n }\n }\n }\n }\n};\n\nexport default plugin;\n"],"mappings":";;;;;;;AACA;AAEA;AACA;AACA;AAGA,MAAMA,MAA+C,GAAG;EACpDC,IAAI,EAAE,gBAAgB;EACtBC,IAAI,EAAE,oCAAoC;EAC1CC,MAAM,EAAE;IACJC,QAAQ,EAAE,aAAe;AACjC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAAS;IACDC,SAAS,EAAE;MACPC,OAAO,EAAE;QACLC,uBAAuB,EAAE,OAAOC,CAAC,EAAEC,IAAS,EAAEC,OAAO,KAAK;UACtD,IAAI;YACA,MAAM,IAAAC,gCAAe,EAACD,OAAO,EAAE;cAAEE,GAAG,EAAE;YAAI,CAAC,CAAC;YAE5C,MAAMC,IAAI,GAAGJ,IAAI,CAACK,IAAgC;YAElD,MAAMC,QAAQ,GAAG,MAAML,OAAO,CAACM,WAAW,CAACC,WAAW,EAAE;YACxD,IAAI,CAACF,QAAQ,EAAE;cACX,MAAM,IAAIG,cAAW,CACjB,gCAAgC,EAChC,6BAA6B,EAC7B;gBAAEL;cAAK,CAAC,CACX;YACL;YAEA,OAAO,IAAIM,mBAAQ,CAAC,IAAAC,gDAAuB,EAACP,IAAI,EAAEE,QAAQ,CAAC,CAAC;UAChE,CAAC,CAAC,OAAOM,CAAC,EAAE;YACR,OAAO,IAAIC,wBAAa,CAAC;cACrBC,OAAO,EAAEF,CAAC,CAACE,OAAO;cAClBC,IAAI,EAAEH,CAAC,CAACG,IAAI;cACZV,IAAI,EAAEO,CAAC,CAACP;YACZ,CAAC,CAAC;UACN;QACJ,CAAC;QACDW,wBAAwB,EAAE,OAAOjB,CAAC,EAAEC,IAAI,EAAEC,OAAO,KAAK;UAClD,MAAM,IAAAC,gCAAe,EAACD,OAAO,EAAE;YAAEE,GAAG,EAAE;UAAI,CAAC,CAAC;UAE5C,MAAMc,KAAK,GAAGjB,IAAI,CAACK,IAAkC;UAErD,IAAI;YACA,MAAMC,QAAQ,GAAG,MAAML,OAAO,CAACM,WAAW,CAACC,WAAW,EAAE;YACxD,IAAI,CAACF,QAAQ,EAAE;cACX,MAAM,IAAIG,cAAW,CACjB,gCAAgC,EAChC,6BAA6B,EAC7B;gBAAEQ;cAAM,CAAC,CACZ;YACL;YAEA,MAAMC,iBAAiB,GAAGD,KAAK,CAACE,GAAG,CAACf,IAAI,IAAI;cACxC,OAAO,IAAAO,gDAAuB,EAACP,IAAI,EAAEE,QAAQ,CAAC;YAClD,CAAC,CAAC;YAEF,OAAO,IAAII,mBAAQ,CAACQ,iBAAiB,CAAC;UAC1C,CAAC,CAAC,OAAON,CAAC,EAAE;YACR,OAAO,IAAIC,wBAAa,CAAC;cACrBC,OAAO,EAAEF,CAAC,CAACE,OAAO;cAClBC,IAAI,EAAEH,CAAC,CAACG,IAAI;cACZV,IAAI,EAAEO,CAAC,CAACP;YACZ,CAAC,CAAC;UACN;QACJ;MACJ;IACJ;EACJ;AACJ,CAAC;AAAC,eAEad,MAAM;AAAA"}
1
+ {"version":3,"names":["plugin","type","name","schema","typeDefs","resolvers","FmQuery","getPreSignedPostPayload","_","args","context","checkPermission","rwd","file","data","settings","fileManager","getSettings","WebinyError","Response","getPresignedPostPayload","e","ErrorResponse","message","code","getPreSignedPostPayloads","files","presignedPayloads","map","FmMutation","createMultiPartUpload","s3Client","S3","region","process","env","AWS_REGION","signatureVersion","useCase","CreateMultiPartUploadUseCase","String","S3_BUCKET","multiPartUpload","execute","numberOfParts","completeMultiPartUpload","CompleteMultiPartUploadUseCase","fileKey","uploadId"],"sources":["graphqlFileStorageS3.ts"],"sourcesContent":["import S3 from \"aws-sdk/clients/s3\";\nimport { GraphQLSchemaPlugin } from \"@webiny/handler-graphql/types\";\nimport { ErrorResponse, Response } from \"@webiny/handler-graphql/responses\";\nimport { FileManagerContext } from \"@webiny/api-file-manager/types\";\nimport { getPresignedPostPayload } from \"~/utils/getPresignedPostPayload\";\nimport WebinyError from \"@webiny/error\";\nimport { checkPermission } from \"~/plugins/checkPermission\";\nimport { PresignedPostPayloadData } from \"~/types\";\nimport { CreateMultiPartUploadUseCase } from \"~/multiPartUpload/CreateMultiPartUploadUseCase\";\nimport { CompleteMultiPartUploadUseCase } from \"~/multiPartUpload/CompleteMultiPartUploadUseCase\";\n\nconst plugin: GraphQLSchemaPlugin<FileManagerContext> = {\n type: \"graphql-schema\",\n name: \"graphql-schema-api-file-manager-s3\",\n schema: {\n typeDefs: /* GraphQL */ `\n input PreSignedPostPayloadInput {\n name: String!\n type: String!\n size: Long!\n }\n\n type GetPreSignedPostPayloadResponseDataFile {\n id: ID!\n name: String!\n type: String!\n size: Long!\n key: String!\n }\n\n type GetPreSignedPostPayloadResponseData {\n # Contains data that is necessary for initiating a file upload.\n data: JSON!\n file: UploadFileResponseDataFile!\n }\n\n type GetPreSignedPostPayloadResponse {\n error: FileError\n data: GetPreSignedPostPayloadResponseData\n }\n\n type MultiPartUploadFilePart {\n partNumber: Int!\n url: String!\n }\n\n type CreateMultiPartUploadResponseData {\n file: GetPreSignedPostPayloadResponseDataFile!\n uploadId: String!\n parts: [MultiPartUploadFilePart!]!\n }\n\n type CompleteMultiPartUploadResponse {\n data: Boolean\n error: FileError\n }\n\n type GetPreSignedPostPayloadsResponse {\n error: FileError\n data: [GetPreSignedPostPayloadResponseData!]!\n }\n\n extend type FmQuery {\n getPreSignedPostPayload(\n data: PreSignedPostPayloadInput!\n ): GetPreSignedPostPayloadResponse\n getPreSignedPostPayloads(\n data: [PreSignedPostPayloadInput]!\n ): GetPreSignedPostPayloadsResponse\n }\n\n type CreateMultiPartUploadResponse {\n data: CreateMultiPartUploadResponseData\n error: FileError\n }\n\n input MultiPartUploadFilePartInput {\n partNumber: Int!\n etag: String!\n }\n\n extend type FmMutation {\n createMultiPartUpload(\n data: PreSignedPostPayloadInput!\n numberOfParts: Number!\n ): CreateMultiPartUploadResponse\n\n completeMultiPartUpload(\n fileKey: String!\n uploadId: String!\n ): CompleteMultiPartUploadResponse\n }\n `,\n resolvers: {\n FmQuery: {\n getPreSignedPostPayload: async (_, args: any, context) => {\n try {\n await checkPermission(context, { rwd: \"w\" });\n\n const file = args.data as PresignedPostPayloadData;\n\n const settings = await context.fileManager.getSettings();\n if (!settings) {\n throw new WebinyError(\n \"Missing File Manager Settings.\",\n \"FILE_MANAGER_SETTINGS_ERROR\",\n { file }\n );\n }\n\n return new Response(getPresignedPostPayload(file, settings));\n } catch (e) {\n return new ErrorResponse({\n message: e.message,\n code: e.code,\n data: e.data\n });\n }\n },\n getPreSignedPostPayloads: async (_, args, context) => {\n await checkPermission(context, { rwd: \"w\" });\n\n const files = args.data as PresignedPostPayloadData[];\n\n try {\n const settings = await context.fileManager.getSettings();\n if (!settings) {\n throw new WebinyError(\n \"Missing File Manager Settings.\",\n \"FILE_MANAGER_SETTINGS_ERROR\",\n { files }\n );\n }\n\n const presignedPayloads = files.map(file => {\n return getPresignedPostPayload(file, settings);\n });\n\n return new Response(presignedPayloads);\n } catch (e) {\n return new ErrorResponse({\n message: e.message,\n code: e.code,\n data: e.data\n });\n }\n }\n },\n FmMutation: {\n createMultiPartUpload: async (_, args, context) => {\n await checkPermission(context, { rwd: \"w\" });\n\n const s3Client = new S3({\n region: process.env.AWS_REGION,\n signatureVersion: \"v4\"\n });\n\n try {\n const useCase = new CreateMultiPartUploadUseCase(\n String(process.env.S3_BUCKET),\n s3Client\n );\n\n const multiPartUpload = await useCase.execute({\n file: args.data,\n numberOfParts: args.numberOfParts\n });\n\n return new Response(multiPartUpload);\n } catch (e) {\n return new ErrorResponse({\n message: e.message,\n code: e.code,\n data: e.data\n });\n }\n },\n completeMultiPartUpload: async (_, args, context) => {\n await checkPermission(context, { rwd: \"w\" });\n\n const s3Client = new S3({\n region: process.env.AWS_REGION,\n signatureVersion: \"v4\"\n });\n\n try {\n const useCase = new CompleteMultiPartUploadUseCase(\n String(process.env.S3_BUCKET),\n s3Client\n );\n\n await useCase.execute({\n fileKey: args.fileKey,\n uploadId: args.uploadId\n });\n\n return new Response(true);\n } catch (e) {\n return new ErrorResponse({\n message: e.message,\n code: e.code,\n data: e.data\n });\n }\n }\n }\n }\n }\n};\n\nexport default plugin;\n"],"mappings":"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"}
package/types.d.ts CHANGED
@@ -7,13 +7,14 @@ export interface PresignedPostPayloadData {
7
7
  key?: string;
8
8
  keyPrefix?: string;
9
9
  }
10
+ export interface FileData {
11
+ id: string;
12
+ name: string;
13
+ key: string;
14
+ type: string;
15
+ size: number;
16
+ }
10
17
  export interface PresignedPostPayloadDataResponse {
11
18
  data: S3.PresignedPost;
12
- file: {
13
- id: string;
14
- name: string;
15
- key: string;
16
- type: string;
17
- size: number;
18
- };
19
+ file: FileData;
19
20
  }
package/types.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"names":[],"sources":["types.ts"],"sourcesContent":["import S3 from \"aws-sdk/clients/s3\";\n\nexport interface PresignedPostPayloadData {\n name: string;\n type: string;\n size: number;\n id?: string;\n key?: string;\n keyPrefix?: string;\n}\n\nexport interface PresignedPostPayloadDataResponse {\n data: S3.PresignedPost;\n file: {\n id: string;\n name: string;\n key: string;\n type: string;\n size: number;\n };\n}\n"],"mappings":""}
1
+ {"version":3,"names":[],"sources":["types.ts"],"sourcesContent":["import S3 from \"aws-sdk/clients/s3\";\n\nexport interface PresignedPostPayloadData {\n name: string;\n type: string;\n size: number;\n id?: string;\n key?: string;\n keyPrefix?: string;\n}\n\nexport interface FileData {\n id: string;\n name: string;\n key: string;\n type: string;\n size: number;\n}\n\nexport interface PresignedPostPayloadDataResponse {\n data: S3.PresignedPost;\n file: FileData;\n}\n"],"mappings":""}
@@ -1,3 +1,3 @@
1
- import { PresignedPostPayloadData, PresignedPostPayloadDataResponse } from "../types";
2
1
  import { FileManagerSettings } from "@webiny/api-file-manager/types";
2
+ import { PresignedPostPayloadData, PresignedPostPayloadDataResponse } from "../types";
3
3
  export declare const getPresignedPostPayload: (data: PresignedPostPayloadData, settings: FileManagerSettings) => PresignedPostPayloadDataResponse;
@@ -5,13 +5,9 @@ Object.defineProperty(exports, "__esModule", {
5
5
  value: true
6
6
  });
7
7
  exports.getPresignedPostPayload = void 0;
8
- var _mdbid = _interopRequireDefault(require("mdbid"));
9
- var _sanitizeFilename = _interopRequireDefault(require("sanitize-filename"));
10
8
  var _s = _interopRequireDefault(require("aws-sdk/clients/s3"));
11
9
  var _validation = require("@webiny/validation");
12
- var _mimeTypes = require("./mimeTypes");
13
- // @ts-ignore `mdbid` has no type declarations
14
-
10
+ var _prepareFileData = require("./prepareFileData");
15
11
  const S3_BUCKET = process.env.S3_BUCKET;
16
12
  const UPLOAD_MAX_FILE_SIZE_DEFAULT = 1099511627776; // 1TB
17
13
 
@@ -25,36 +21,7 @@ const sanitizeFileSizeValue = (value, defaultValue) => {
25
21
  }
26
22
  };
27
23
  const getPresignedPostPayload = (data, settings) => {
28
- // If type is missing, let's use the default "application/octet-stream" type,
29
- // which is also the default type that the Amazon S3 would use.
30
- if (!data.type) {
31
- data.type = "application/octet-stream";
32
- }
33
- const contentType = data.type;
34
- if (!contentType) {
35
- throw Error(`File's content type could not be resolved.`);
36
- }
37
- const id = data.id || (0, _mdbid.default)();
38
- let key = data.key || (0, _sanitizeFilename.default)(data.name);
39
-
40
- // We must prefix file key with file ID.
41
- if (!key.startsWith(id)) {
42
- key = id + "/" + key;
43
- }
44
- if (data.keyPrefix) {
45
- key = data.keyPrefix + key;
46
- }
47
-
48
- // Replace all whitespace.
49
- key = key.replace(/\s/g, "");
50
-
51
- // Make sure file key contains a file extension
52
- const extensions = _mimeTypes.mimeTypes[contentType];
53
- // We only need this variable to compare extensions in a case-insensitive way.
54
- const lowerKey = key.toLowerCase();
55
- if (!extensions.some(ext => lowerKey.endsWith(`.${ext}`))) {
56
- key = key + `.${extensions[0]}`;
57
- }
24
+ const file = (0, _prepareFileData.prepareFileData)(data);
58
25
  const uploadMinFileSize = sanitizeFileSizeValue(settings.uploadMinFileSize, 0);
59
26
  const uploadMaxFileSize = sanitizeFileSizeValue(settings.uploadMaxFileSize, UPLOAD_MAX_FILE_SIZE_DEFAULT);
60
27
  const params = {
@@ -62,8 +29,8 @@ const getPresignedPostPayload = (data, settings) => {
62
29
  Bucket: S3_BUCKET,
63
30
  Conditions: [["content-length-range", uploadMinFileSize, uploadMaxFileSize]],
64
31
  Fields: {
65
- "Content-Type": contentType,
66
- key
32
+ "Content-Type": file.type,
33
+ key: file.key
67
34
  }
68
35
  };
69
36
  if (params.Fields.key.startsWith("/")) {
@@ -73,13 +40,7 @@ const getPresignedPostPayload = (data, settings) => {
73
40
  const payload = s3.createPresignedPost(params);
74
41
  return {
75
42
  data: payload,
76
- file: {
77
- id,
78
- name: data.name,
79
- key,
80
- type: contentType,
81
- size: data.size
82
- }
43
+ file
83
44
  };
84
45
  };
85
46
  exports.getPresignedPostPayload = getPresignedPostPayload;
@@ -1 +1 @@
1
- {"version":3,"names":["S3_BUCKET","process","env","UPLOAD_MAX_FILE_SIZE_DEFAULT","sanitizeFileSizeValue","value","defaultValue","validation","validateSync","e","getPresignedPostPayload","data","settings","type","contentType","Error","id","mdbid","key","sanitizeFilename","name","startsWith","keyPrefix","replace","extensions","mimeTypes","lowerKey","toLowerCase","some","ext","endsWith","uploadMinFileSize","uploadMaxFileSize","params","Expires","Bucket","Conditions","Fields","slice","s3","S3","payload","createPresignedPost","file","size"],"sources":["getPresignedPostPayload.ts"],"sourcesContent":["// @ts-ignore `mdbid` has no type declarations\nimport mdbid from \"mdbid\";\nimport sanitizeFilename from \"sanitize-filename\";\nimport S3 from \"aws-sdk/clients/s3\";\nimport { validation } from \"@webiny/validation\";\nimport { PresignedPostPayloadData, PresignedPostPayloadDataResponse } from \"~/types\";\nimport { FileManagerSettings } from \"@webiny/api-file-manager/types\";\nimport { mimeTypes } from \"./mimeTypes\";\n\nconst S3_BUCKET = process.env.S3_BUCKET;\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 (e) {\n // TODO @ts-refactor No need to log the error?\n return defaultValue;\n }\n};\n\nexport const getPresignedPostPayload = (\n data: PresignedPostPayloadData,\n settings: FileManagerSettings\n): PresignedPostPayloadDataResponse => {\n // If type is missing, let's use the default \"application/octet-stream\" type,\n // which is also the default type that the Amazon S3 would use.\n if (!data.type) {\n data.type = \"application/octet-stream\";\n }\n\n const contentType = data.type;\n if (!contentType) {\n throw Error(`File's content type could not be resolved.`);\n }\n\n const id = data.id || mdbid();\n let key = data.key || sanitizeFilename(data.name);\n\n // We must prefix file key with file ID.\n if (!key.startsWith(id)) {\n key = id + \"/\" + key;\n }\n\n if (data.keyPrefix) {\n key = data.keyPrefix + key;\n }\n\n // Replace all whitespace.\n key = key.replace(/\\s/g, \"\");\n\n // Make sure file key contains a file extension\n const extensions = mimeTypes[contentType];\n // We only need this variable to compare extensions in a case-insensitive way.\n const lowerKey = key.toLowerCase();\n if (!extensions.some(ext => lowerKey.endsWith(`.${ext}`))) {\n key = key + `.${extensions[0]}`;\n }\n\n const uploadMinFileSize = sanitizeFileSizeValue(settings.uploadMinFileSize, 0);\n const uploadMaxFileSize = sanitizeFileSizeValue(\n settings.uploadMaxFileSize,\n UPLOAD_MAX_FILE_SIZE_DEFAULT\n );\n\n const params = {\n Expires: 60,\n Bucket: S3_BUCKET,\n Conditions: [[\"content-length-range\", uploadMinFileSize, uploadMaxFileSize]],\n Fields: {\n \"Content-Type\": contentType,\n key\n }\n };\n\n if (params.Fields.key.startsWith(\"/\")) {\n params.Fields.key = params.Fields.key.slice(1);\n }\n\n const s3 = new S3();\n const payload = s3.createPresignedPost(params);\n\n return {\n data: payload,\n file: {\n id,\n name: data.name,\n key,\n type: contentType,\n size: data.size\n }\n };\n};\n"],"mappings":"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"}
1
+ {"version":3,"names":["S3_BUCKET","process","env","UPLOAD_MAX_FILE_SIZE_DEFAULT","sanitizeFileSizeValue","value","defaultValue","validation","validateSync","e","getPresignedPostPayload","data","settings","file","prepareFileData","uploadMinFileSize","uploadMaxFileSize","params","Expires","Bucket","Conditions","Fields","type","key","startsWith","slice","s3","S3","payload","createPresignedPost"],"sources":["getPresignedPostPayload.ts"],"sourcesContent":["import S3 from \"aws-sdk/clients/s3\";\nimport { validation } from \"@webiny/validation\";\nimport { FileManagerSettings } from \"@webiny/api-file-manager/types\";\nimport { prepareFileData } from \"~/utils/prepareFileData\";\nimport { PresignedPostPayloadData, PresignedPostPayloadDataResponse } from \"~/types\";\n\nconst S3_BUCKET = process.env.S3_BUCKET;\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 (e) {\n // TODO @ts-refactor No need to log the error?\n return defaultValue;\n }\n};\n\nexport const getPresignedPostPayload = (\n data: PresignedPostPayloadData,\n settings: FileManagerSettings\n): PresignedPostPayloadDataResponse => {\n const file = prepareFileData(data);\n\n const uploadMinFileSize = sanitizeFileSizeValue(settings.uploadMinFileSize, 0);\n const uploadMaxFileSize = sanitizeFileSizeValue(\n settings.uploadMaxFileSize,\n UPLOAD_MAX_FILE_SIZE_DEFAULT\n );\n\n const params = {\n Expires: 60,\n Bucket: S3_BUCKET,\n Conditions: [[\"content-length-range\", uploadMinFileSize, uploadMaxFileSize]],\n Fields: {\n \"Content-Type\": file.type,\n key: file.key\n }\n };\n\n if (params.Fields.key.startsWith(\"/\")) {\n params.Fields.key = params.Fields.key.slice(1);\n }\n\n const s3 = new S3();\n const payload = s3.createPresignedPost(params);\n\n return {\n data: payload,\n file\n };\n};\n"],"mappings":";;;;;;;AAAA;AACA;AAEA;AAGA,MAAMA,SAAS,GAAGC,OAAO,CAACC,GAAG,CAACF,SAAS;AACvC,MAAMG,4BAA4B,GAAG,aAAa,CAAC,CAAC;;AAEpD,MAAMC,qBAAqB,GAAG,CAACC,KAAa,EAAEC,YAAoB,KAAa;EAC3E,IAAI;IACAC,sBAAU,CAACC,YAAY,CAACH,KAAK,EAAE,wBAAwB,CAAC;IACxD,OAAOA,KAAK;EAChB,CAAC,CAAC,OAAOI,CAAC,EAAE;IACR;IACA,OAAOH,YAAY;EACvB;AACJ,CAAC;AAEM,MAAMI,uBAAuB,GAAG,CACnCC,IAA8B,EAC9BC,QAA6B,KACM;EACnC,MAAMC,IAAI,GAAG,IAAAC,gCAAe,EAACH,IAAI,CAAC;EAElC,MAAMI,iBAAiB,GAAGX,qBAAqB,CAACQ,QAAQ,CAACG,iBAAiB,EAAE,CAAC,CAAC;EAC9E,MAAMC,iBAAiB,GAAGZ,qBAAqB,CAC3CQ,QAAQ,CAACI,iBAAiB,EAC1Bb,4BAA4B,CAC/B;EAED,MAAMc,MAAM,GAAG;IACXC,OAAO,EAAE,EAAE;IACXC,MAAM,EAAEnB,SAAS;IACjBoB,UAAU,EAAE,CAAC,CAAC,sBAAsB,EAAEL,iBAAiB,EAAEC,iBAAiB,CAAC,CAAC;IAC5EK,MAAM,EAAE;MACJ,cAAc,EAAER,IAAI,CAACS,IAAI;MACzBC,GAAG,EAAEV,IAAI,CAACU;IACd;EACJ,CAAC;EAED,IAAIN,MAAM,CAACI,MAAM,CAACE,GAAG,CAACC,UAAU,CAAC,GAAG,CAAC,EAAE;IACnCP,MAAM,CAACI,MAAM,CAACE,GAAG,GAAGN,MAAM,CAACI,MAAM,CAACE,GAAG,CAACE,KAAK,CAAC,CAAC,CAAC;EAClD;EAEA,MAAMC,EAAE,GAAG,IAAIC,UAAE,EAAE;EACnB,MAAMC,OAAO,GAAGF,EAAE,CAACG,mBAAmB,CAACZ,MAAM,CAAC;EAE9C,OAAO;IACHN,IAAI,EAAEiB,OAAO;IACbf;EACJ,CAAC;AACL,CAAC;AAAC"}
@@ -0,0 +1,2 @@
1
+ import { PresignedPostPayloadData, FileData } from "../types";
2
+ export declare const prepareFileData: (data: PresignedPostPayloadData) => FileData;
@@ -0,0 +1,62 @@
1
+ "use strict";
2
+
3
+ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault").default;
4
+ Object.defineProperty(exports, "__esModule", {
5
+ value: true
6
+ });
7
+ exports.prepareFileData = void 0;
8
+ var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
9
+ var _sanitizeFilename = _interopRequireDefault(require("sanitize-filename"));
10
+ var _utils = require("@webiny/utils");
11
+ var _mimeTypes = require("./mimeTypes");
12
+ class FileKey {
13
+ constructor(name, type) {
14
+ (0, _defineProperty2.default)(this, "name", void 0);
15
+ (0, _defineProperty2.default)(this, "type", void 0);
16
+ (0, _defineProperty2.default)(this, "prefix", void 0);
17
+ (0, _defineProperty2.default)(this, "id", void 0);
18
+ (0, _defineProperty2.default)(this, "extension", "");
19
+ this.type = type;
20
+ this.name = name;
21
+ }
22
+ setId(id) {
23
+ if (!this.name.startsWith(`${id}/`)) {
24
+ this.id = id;
25
+ }
26
+ }
27
+ setPrefix(prefix) {
28
+ this.prefix = prefix;
29
+ }
30
+ getKey() {
31
+ const key = (0, _sanitizeFilename.default)(this.name).replace(/\s/g, "");
32
+ const maybeHasExtension = key.toLowerCase().includes(".");
33
+ if (maybeHasExtension) {
34
+ const maybeExt = key.toLowerCase().split(".").pop();
35
+ const extensions = _mimeTypes.mimeTypes[this.type];
36
+ if (extensions && !extensions.includes(maybeExt)) {
37
+ this.extension = extensions[0];
38
+ }
39
+ }
40
+ const keyWithExt = [key, this.extension].filter(Boolean).join(".");
41
+ return [this.prefix, this.id, keyWithExt].filter(Boolean).join("/");
42
+ }
43
+ }
44
+ const prepareFileData = data => {
45
+ // If type is missing, let's use the default "application/octet-stream" type,
46
+ // which is also the default type that the Amazon S3 would use.
47
+ const contentType = data.type || "application/octet-stream";
48
+ const id = data.id || (0, _utils.mdbid)();
49
+ const key = new FileKey(data.key || data.name, data.type);
50
+ key.setId(id);
51
+ if (data.keyPrefix) {
52
+ key.setPrefix(data.keyPrefix);
53
+ }
54
+ return {
55
+ id,
56
+ name: data.name,
57
+ key: key.getKey(),
58
+ type: contentType,
59
+ size: data.size
60
+ };
61
+ };
62
+ exports.prepareFileData = prepareFileData;
@@ -0,0 +1 @@
1
+ {"version":3,"names":["FileKey","constructor","name","type","setId","id","startsWith","setPrefix","prefix","getKey","key","sanitizeFilename","replace","maybeHasExtension","toLowerCase","includes","maybeExt","split","pop","extensions","mimeTypes","extension","keyWithExt","filter","Boolean","join","prepareFileData","data","contentType","mdbid","keyPrefix","size"],"sources":["prepareFileData.ts"],"sourcesContent":["import sanitizeFilename from \"sanitize-filename\";\nimport { mdbid } from \"@webiny/utils\";\nimport { PresignedPostPayloadData, FileData } from \"~/types\";\nimport { mimeTypes } from \"./mimeTypes\";\n\nclass FileKey {\n private readonly name: string;\n private readonly type: string;\n private prefix: string | undefined;\n private id: string | undefined;\n private extension = \"\";\n\n constructor(name: string, type: string) {\n this.type = type;\n this.name = name;\n }\n\n setId(id: string) {\n if (!this.name.startsWith(`${id}/`)) {\n this.id = id;\n }\n }\n\n setPrefix(prefix: string) {\n this.prefix = prefix;\n }\n\n getKey() {\n const key = sanitizeFilename(this.name).replace(/\\s/g, \"\");\n const maybeHasExtension = key.toLowerCase().includes(\".\");\n\n if (maybeHasExtension) {\n const maybeExt = key.toLowerCase().split(\".\").pop() as string;\n const extensions = mimeTypes[this.type];\n if (extensions && !extensions.includes(maybeExt)) {\n this.extension = extensions[0];\n }\n }\n\n const keyWithExt = [key, this.extension].filter(Boolean).join(\".\");\n return [this.prefix, this.id, keyWithExt].filter(Boolean).join(\"/\");\n }\n}\n\nexport const prepareFileData = (data: PresignedPostPayloadData): FileData => {\n // If type is missing, let's use the default \"application/octet-stream\" type,\n // which is also the default type that the Amazon S3 would use.\n const contentType = data.type || \"application/octet-stream\";\n\n const id = data.id || mdbid();\n const key = new FileKey(data.key || data.name, data.type);\n\n key.setId(id);\n\n if (data.keyPrefix) {\n key.setPrefix(data.keyPrefix);\n }\n\n return {\n id,\n name: data.name,\n key: key.getKey(),\n type: contentType,\n size: data.size\n };\n};\n"],"mappings":";;;;;;;;AAAA;AACA;AAEA;AAEA,MAAMA,OAAO,CAAC;EAOVC,WAAW,CAACC,IAAY,EAAEC,IAAY,EAAE;IAAA;IAAA;IAAA;IAAA;IAAA,iDAFpB,EAAE;IAGlB,IAAI,CAACA,IAAI,GAAGA,IAAI;IAChB,IAAI,CAACD,IAAI,GAAGA,IAAI;EACpB;EAEAE,KAAK,CAACC,EAAU,EAAE;IACd,IAAI,CAAC,IAAI,CAACH,IAAI,CAACI,UAAU,CAAE,GAAED,EAAG,GAAE,CAAC,EAAE;MACjC,IAAI,CAACA,EAAE,GAAGA,EAAE;IAChB;EACJ;EAEAE,SAAS,CAACC,MAAc,EAAE;IACtB,IAAI,CAACA,MAAM,GAAGA,MAAM;EACxB;EAEAC,MAAM,GAAG;IACL,MAAMC,GAAG,GAAG,IAAAC,yBAAgB,EAAC,IAAI,CAACT,IAAI,CAAC,CAACU,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC;IAC1D,MAAMC,iBAAiB,GAAGH,GAAG,CAACI,WAAW,EAAE,CAACC,QAAQ,CAAC,GAAG,CAAC;IAEzD,IAAIF,iBAAiB,EAAE;MACnB,MAAMG,QAAQ,GAAGN,GAAG,CAACI,WAAW,EAAE,CAACG,KAAK,CAAC,GAAG,CAAC,CAACC,GAAG,EAAY;MAC7D,MAAMC,UAAU,GAAGC,oBAAS,CAAC,IAAI,CAACjB,IAAI,CAAC;MACvC,IAAIgB,UAAU,IAAI,CAACA,UAAU,CAACJ,QAAQ,CAACC,QAAQ,CAAC,EAAE;QAC9C,IAAI,CAACK,SAAS,GAAGF,UAAU,CAAC,CAAC,CAAC;MAClC;IACJ;IAEA,MAAMG,UAAU,GAAG,CAACZ,GAAG,EAAE,IAAI,CAACW,SAAS,CAAC,CAACE,MAAM,CAACC,OAAO,CAAC,CAACC,IAAI,CAAC,GAAG,CAAC;IAClE,OAAO,CAAC,IAAI,CAACjB,MAAM,EAAE,IAAI,CAACH,EAAE,EAAEiB,UAAU,CAAC,CAACC,MAAM,CAACC,OAAO,CAAC,CAACC,IAAI,CAAC,GAAG,CAAC;EACvE;AACJ;AAEO,MAAMC,eAAe,GAAIC,IAA8B,IAAe;EACzE;EACA;EACA,MAAMC,WAAW,GAAGD,IAAI,CAACxB,IAAI,IAAI,0BAA0B;EAE3D,MAAME,EAAE,GAAGsB,IAAI,CAACtB,EAAE,IAAI,IAAAwB,YAAK,GAAE;EAC7B,MAAMnB,GAAG,GAAG,IAAIV,OAAO,CAAC2B,IAAI,CAACjB,GAAG,IAAIiB,IAAI,CAACzB,IAAI,EAAEyB,IAAI,CAACxB,IAAI,CAAC;EAEzDO,GAAG,CAACN,KAAK,CAACC,EAAE,CAAC;EAEb,IAAIsB,IAAI,CAACG,SAAS,EAAE;IAChBpB,GAAG,CAACH,SAAS,CAACoB,IAAI,CAACG,SAAS,CAAC;EACjC;EAEA,OAAO;IACHzB,EAAE;IACFH,IAAI,EAAEyB,IAAI,CAACzB,IAAI;IACfQ,GAAG,EAAEA,GAAG,CAACD,MAAM,EAAE;IACjBN,IAAI,EAAEyB,WAAW;IACjBG,IAAI,EAAEJ,IAAI,CAACI;EACf,CAAC;AACL,CAAC;AAAC"}