@qrvey/object-storage 0.0.10-beta.2 → 0.0.10-beta.3

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.
@@ -1,6 +1,6 @@
1
1
  import stream from 'stream';
2
2
  import { BlobServiceClient, BlobSASPermissions } from '@azure/storage-blob';
3
- import { S3Client, S3, ListObjectsV2Command, HeadObjectCommand, GetObjectCommand, PutObjectCommand, DeleteObjectCommand, HeadBucketCommand } from '@aws-sdk/client-s3';
3
+ import { S3Client, S3, ListObjectsV2Command, HeadObjectCommand, GetObjectCommand, PutObjectCommand, DeleteObjectCommand, HeadBucketCommand, UploadPartCommand } from '@aws-sdk/client-s3';
4
4
  import { getSignedUrl } from '@aws-sdk/s3-request-presigner';
5
5
  import { Upload } from '@aws-sdk/lib-storage';
6
6
 
@@ -10,6 +10,11 @@ var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
10
10
  var __getOwnPropSymbols = Object.getOwnPropertySymbols;
11
11
  var __hasOwnProp = Object.prototype.hasOwnProperty;
12
12
  var __propIsEnum = Object.prototype.propertyIsEnumerable;
13
+ var __knownSymbol = (name, symbol) => {
14
+ if (symbol = Symbol[name])
15
+ return symbol;
16
+ throw Error("Symbol." + name + " is not defined");
17
+ };
13
18
  var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
14
19
  var __spreadValues = (a, b) => {
15
20
  for (var prop in b || (b = {}))
@@ -35,6 +40,7 @@ var __objRest = (source, exclude) => {
35
40
  }
36
41
  return target;
37
42
  };
43
+ var __forAwait = (obj, it, method) => (it = obj[__knownSymbol("asyncIterator")]) ? it.call(obj) : (obj = obj[__knownSymbol("iterator")](), it = {}, method = (key, fn) => (fn = obj[key]) && (it[key] = (arg) => new Promise((yes, no, done) => (arg = fn.call(obj, arg), done = arg.done, Promise.resolve(arg.value).then((value) => yes({ value, done }), no)))), method("next"), method("return"), it);
38
44
 
39
45
  // src/shared/utils/errorHandler.ts
40
46
  var errorMessages = {
@@ -447,6 +453,71 @@ var BlobStorageService = class {
447
453
  );
448
454
  }
449
455
  }
456
+ async listMultipartUploadsForBucket() {
457
+ const containerClient = this.blobServiceClient.getContainerClient(
458
+ this.containerName
459
+ );
460
+ const blobList = containerClient.listBlobsFlat();
461
+ const uploads = [];
462
+ try {
463
+ for (var iter = __forAwait(blobList), more, temp, error; more = !(temp = await iter.next()).done; more = false) {
464
+ const blob = temp.value;
465
+ uploads.push({
466
+ uploadId: blob.name,
467
+ key: blob.name,
468
+ initiated: blob.properties.createdOn || /* @__PURE__ */ new Date()
469
+ });
470
+ }
471
+ } catch (temp) {
472
+ error = [temp];
473
+ } finally {
474
+ try {
475
+ more && (temp = iter.return) && await temp.call(iter);
476
+ } finally {
477
+ if (error)
478
+ throw error[0];
479
+ }
480
+ }
481
+ return {
482
+ bucketName: this.containerName,
483
+ uploads
484
+ };
485
+ }
486
+ /**
487
+ * Retrieves the list of parts for a multipart upload.
488
+ *
489
+ * @param {string} blobName - The name of the blob (file) in Azure Blob Storage.
490
+ * @return {Promise<ListPartsMultipartUploadResponse>} A promise that resolves to the list of parts for the multipart upload.
491
+ */
492
+ async listMultipartUploadsForKey(blobName) {
493
+ var _a;
494
+ const containerClient = this.blobServiceClient.getContainerClient(
495
+ this.containerName
496
+ );
497
+ const blobClient = containerClient.getBlockBlobClient(blobName);
498
+ const listResponse = await blobClient.getBlockList("all");
499
+ const parts = ((_a = listResponse == null ? void 0 : listResponse.committedBlocks) == null ? void 0 : _a.map((block, index) => ({
500
+ PartNumber: index + 1,
501
+ LastModified: /* @__PURE__ */ new Date(),
502
+ // Azure Blob Storage doesn't provide the last modified date for individual parts
503
+ ETag: block.name,
504
+ Size: block.size
505
+ }))) || [];
506
+ return {
507
+ Parts: parts
508
+ };
509
+ }
510
+ /**
511
+ * Generates a unique upload ID for multipart uploads.
512
+ *
513
+ * @return {Promise<string>} A promise that resolves to a unique upload ID.
514
+ */
515
+ async generateUploadIdMultipart() {
516
+ const timestamp = Date.now();
517
+ const randomNum = Math.floor(Math.random() * 100);
518
+ const blockIdBase = (timestamp - randomNum).toString();
519
+ return blockIdBase;
520
+ }
450
521
  /**
451
522
  * Uploads a part of a file as a block to Azure Blob Storage and updates the metadata with the block ID.
452
523
  *
@@ -461,17 +532,10 @@ var BlobStorageService = class {
461
532
  this.containerName
462
533
  );
463
534
  const blobClient = containerClient.getBlockBlobClient(blobName);
464
- let blockIdBase = uploadId;
465
- if (!blockIdBase) {
466
- const timestamp = Date.now();
467
- const randomNum = Math.floor(Math.random() * 100);
468
- blockIdBase = (timestamp - randomNum).toString();
469
- }
535
+ const blockIdBase = uploadId || await this.generateUploadIdMultipart();
470
536
  const partId = partNumber.toString().padStart(6, "0");
471
537
  const partIdBase64 = Buffer.from(partId).toString("base64");
472
538
  await blobClient.stageBlock(partIdBase64, file, file.length);
473
- const blockIdStorage = BlockIdStorage.getInstance();
474
- blockIdStorage.addBlockId(blockIdBase, partIdBase64);
475
539
  return blockIdBase;
476
540
  }
477
541
  /**
@@ -483,17 +547,17 @@ var BlobStorageService = class {
483
547
  * @throws {Error} If no block IDs are found in the metadata.
484
548
  */
485
549
  async completeMultipartUpload(blobName, uploadId) {
550
+ var _a;
486
551
  const containerClient = this.blobServiceClient.getContainerClient(
487
552
  this.containerName
488
553
  );
489
554
  const blobClient = containerClient.getBlockBlobClient(blobName);
490
- const blockIdStorage = BlockIdStorage.getInstance();
491
- const blockIds = blockIdStorage.getBlockIds(uploadId);
555
+ const listMultipartUploads = await this.listMultipartUploadsForKey(blobName);
556
+ const blockIds = ((_a = listMultipartUploads == null ? void 0 : listMultipartUploads.Parts) == null ? void 0 : _a.map((part) => part.ETag)) || [];
492
557
  if (blockIds.length === 0) {
493
558
  throw new Error("No block IDs found in metadata.");
494
559
  }
495
560
  await blobClient.commitBlockList(blockIds);
496
- blockIdStorage.clearBlockIds(uploadId);
497
561
  }
498
562
  /**
499
563
  * Aborts a multipart upload by deleting the specified blob and clearing its block IDs metadata.
@@ -511,6 +575,17 @@ var BlobStorageService = class {
511
575
  blockIdStorage.clearBlockIds(uploadId);
512
576
  await blobClient.delete();
513
577
  }
578
+ async getMultipartUploadPresignedUrl(blobName, uploadId, partNumber, expiresInMinutes = 2) {
579
+ const partId = partNumber.toString().padStart(6, "0");
580
+ const partIdBase64 = Buffer.from(partId).toString("base64");
581
+ const sasUrl = await this.getSignatureUrl(
582
+ blobName,
583
+ expiresInMinutes,
584
+ "w"
585
+ );
586
+ const url = `${sasUrl}&comp=block&blockid=${partIdBase64}`;
587
+ return url;
588
+ }
514
589
  };
515
590
 
516
591
  // src/services/storage/s3/s3Helpers.ts
@@ -767,18 +842,69 @@ var S3StorageService = class {
767
842
  );
768
843
  }
769
844
  }
845
+ /**
846
+ * Generates an upload ID for multipart upload in the S3 bucket.
847
+ *
848
+ * @param {string} key - The key of the object to upload.
849
+ * @return {Promise<string>} A promise that resolves to the generated upload ID.
850
+ * @throws {Error} If no upload ID was generated.
851
+ */
852
+ async generateUploadIdMultipart(key) {
853
+ const params = {
854
+ Bucket: this.bucketName,
855
+ Key: key
856
+ };
857
+ const response = await this.s3.createMultipartUpload(params);
858
+ if (!(response == null ? void 0 : response.UploadId))
859
+ throw new Error("No upload ID was generated");
860
+ return response.UploadId;
861
+ }
862
+ async listMultipartUploadsForBucket() {
863
+ const params = {
864
+ Bucket: this.bucketName
865
+ };
866
+ const response = await this.s3.listMultipartUploads(params);
867
+ return {
868
+ bucketName: this.bucketName,
869
+ uploads: response.Uploads ? response.Uploads.map((upload) => {
870
+ var _a, _b;
871
+ return {
872
+ uploadId: upload.UploadId || "",
873
+ key: upload.Key || "",
874
+ initiator: ((_a = upload == null ? void 0 : upload.Initiator) == null ? void 0 : _a.ID) || "",
875
+ owner: ((_b = upload == null ? void 0 : upload.Owner) == null ? void 0 : _b.ID) || "",
876
+ storageClass: upload.StorageClass || "",
877
+ initiated: upload.Initiated || ""
878
+ };
879
+ }) : []
880
+ };
881
+ }
882
+ /**
883
+ * Retrieves the list of parts for a multipart upload.
884
+ *
885
+ * @param {string} key - The key of the object being uploaded.
886
+ * @param {string} uploadId - The ID of the multipart upload.
887
+ * @return {Promise<ListPartsMultipartUploadResponse>} A promise that resolves to the list of parts for the multipart upload.
888
+ */
889
+ async listMultipartUploadsForKey(key, uploadId) {
890
+ const params = {
891
+ Bucket: this.bucketName,
892
+ Key: key,
893
+ UploadId: uploadId
894
+ };
895
+ const response = await this.s3.listParts(params);
896
+ const parts = response.Parts ? response.Parts.map((part) => ({
897
+ PartNumber: part.PartNumber,
898
+ LastModified: part.LastModified,
899
+ ETag: part.ETag,
900
+ Size: part.Size
901
+ })) : [];
902
+ return {
903
+ Parts: parts
904
+ };
905
+ }
770
906
  async uploadMultipart(key, file, partNumber, uploadId) {
771
- let upId = uploadId;
772
- if (!upId) {
773
- const params2 = {
774
- Bucket: this.bucketName,
775
- Key: key
776
- };
777
- const response = await this.s3.createMultipartUpload(params2);
778
- if (!(response == null ? void 0 : response.UploadId))
779
- throw new Error("No upload ID was generated");
780
- upId = response.UploadId;
781
- }
907
+ const upId = uploadId || await this.generateUploadIdMultipart(key);
782
908
  const params = {
783
909
  Bucket: this.bucketName,
784
910
  Key: key,
@@ -790,12 +916,10 @@ var S3StorageService = class {
790
916
  return upId;
791
917
  }
792
918
  async completeMultipartUpload(key, uploadId) {
793
- const listPartsParams = {
794
- Bucket: this.bucketName,
795
- Key: key,
796
- UploadId: uploadId
797
- };
798
- const partsResponse = await this.s3.listParts(listPartsParams);
919
+ const partsResponse = await this.listMultipartUploadsForKey(
920
+ key,
921
+ uploadId
922
+ );
799
923
  const partsList = (partsResponse == null ? void 0 : partsResponse.Parts) && partsResponse.Parts.map(
800
924
  // eslint-disable-next-line no-unused-vars, @typescript-eslint/no-unused-vars
801
925
  (_a) => {
@@ -803,11 +927,14 @@ var S3StorageService = class {
803
927
  return partList;
804
928
  }
805
929
  );
806
- const completeMultipartParams = __spreadProps(__spreadValues({}, listPartsParams), {
930
+ const completeMultipartParams = {
931
+ Bucket: this.bucketName,
932
+ Key: key,
933
+ UploadId: uploadId,
807
934
  MultipartUpload: {
808
935
  Parts: partsList
809
936
  }
810
- });
937
+ };
811
938
  await this.s3.completeMultipartUpload(completeMultipartParams);
812
939
  }
813
940
  async abortMultipartUpload(key, uploadId) {
@@ -818,6 +945,21 @@ var S3StorageService = class {
818
945
  };
819
946
  await this.s3.abortMultipartUpload(params);
820
947
  }
948
+ async getMultipartUploadPresignedUrl(key, uploadId, partNumber, expiresInMinutes = 60) {
949
+ const uploadPartParams = {
950
+ Bucket: this.bucketName,
951
+ Key: key,
952
+ UploadId: uploadId,
953
+ PartNumber: parseInt(partNumber, 10)
954
+ };
955
+ const expiresIn = expiresInMinutes * 60;
956
+ const presignedUrl = await getSignedUrl(
957
+ this.s3Client,
958
+ new UploadPartCommand(uploadPartParams),
959
+ { expiresIn }
960
+ );
961
+ return presignedUrl;
962
+ }
821
963
  };
822
964
 
823
965
  // src/shared/utils/constants.ts
@@ -996,6 +1138,44 @@ var ObjectStorageService = class _ObjectStorageService {
996
1138
  bucketName
997
1139
  ).then((instance) => instance.getHeadBucket());
998
1140
  }
1141
+ /**
1142
+ * Generates a unique upload ID for a multipart upload.
1143
+ *
1144
+ * @param {string} key - The key of the object to upload.
1145
+ * @param {string} [bucketName] - The name of the bucket. If not provided, the default bucket name will be used.
1146
+ * @return {Promise<string>} A promise that resolves to the generated upload ID.
1147
+ */
1148
+ static async generateUploadIdMultipart(key, bucketName) {
1149
+ return _ObjectStorageService.getObjectStorageServiceInstance(
1150
+ bucketName
1151
+ ).then((instance) => instance.generateUploadIdMultipart(key));
1152
+ }
1153
+ /**
1154
+ * Retrieves a list of multipart uploads for a specified key in the object storage service.
1155
+ *
1156
+ * @param {string} key - The key of the object to retrieve uploads for.
1157
+ * @param {string} [bucketName] - The name of the bucket. If not provided, the default bucket name will be used.
1158
+ * @param {string} [uploadId] - The upload ID to filter the results by.
1159
+ * @return {Promise<ListPartsMultipartUploadResponse>} A promise that resolves to the list of multipart uploads for the specified key.
1160
+ */
1161
+ static async listMultipartUploadsForKey(key, bucketName, uploadId) {
1162
+ return _ObjectStorageService.getObjectStorageServiceInstance(
1163
+ bucketName
1164
+ ).then(
1165
+ (instance) => instance.listMultipartUploadsForKey(key, uploadId)
1166
+ );
1167
+ }
1168
+ /**
1169
+ * Retrieves a list of all multipart uploads for a specified bucket in the object storage service.
1170
+ *
1171
+ * @param {string} [bucketName] - The name of the bucket. If not provided, the default bucket name will be used.
1172
+ * @return {Promise<ListMultipartUploadsResponse>} A promise that resolves to the list of multipart uploads for the specified bucket.
1173
+ */
1174
+ static async listMultipartUploadsForBucket(bucketName) {
1175
+ return _ObjectStorageService.getObjectStorageServiceInstance(
1176
+ bucketName
1177
+ ).then((instance) => instance.listMultipartUploadsForBucket());
1178
+ }
999
1179
  /**
1000
1180
  * Uploads a multipart file to the specified bucket in the object storage service.
1001
1181
  *
@@ -1039,6 +1219,25 @@ var ObjectStorageService = class _ObjectStorageService {
1039
1219
  bucketName
1040
1220
  ).then((instance) => instance.abortMultipartUpload(key, uploadId));
1041
1221
  }
1222
+ /**
1223
+ * Retrieves a presigned URL for a specific part of a multipart upload.
1224
+ *
1225
+ * @param {string} key - The key of the object for which to generate the presigned URL.
1226
+ * @param {string} uploadId - The ID of the multipart upload.
1227
+ * @param {string} partNumber - The number of the part for which to generate the presigned URL.
1228
+ * @param {number} [expiresInMinutes] - The number of minutes until the presigned URL expires. Default is 60 minutes.
1229
+ * @return {Promise<string>} A Promise that resolves to the presigned URL for the specified part of the multipart upload.
1230
+ */
1231
+ static async getMultipartUploadPresignedUrl(key, uploadId, partNumber, expiresInMinutes) {
1232
+ return _ObjectStorageService.getObjectStorageServiceInstance().then(
1233
+ (instance) => instance.getMultipartUploadPresignedUrl(
1234
+ key,
1235
+ uploadId,
1236
+ partNumber,
1237
+ expiresInMinutes
1238
+ )
1239
+ );
1240
+ }
1042
1241
  };
1043
1242
 
1044
1243
  export { ObjectStorageService };