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

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 = {
@@ -176,16 +182,28 @@ var BlobStorageService = class {
176
182
  * Retrieves an object from the blob storage service.
177
183
  *
178
184
  * @param {string} blobName - The name of the blob to retrieve.
185
+ * @param {Object} [options] - The options that you can pass to the library.
179
186
  * @return {Promise<GetObjectResponse>} A promise that resolves to the object data, including the body, metadata, content type, and content length, or rejects with an error if there was an issue.
180
187
  */
181
- async getObject(blobName) {
188
+ async getObject(blobName, options) {
182
189
  var _a;
183
190
  try {
191
+ let downloadBlockBlobResponse;
184
192
  const containerClient = this.blobServiceClient.getContainerClient(
185
193
  this.containerName
186
194
  );
187
195
  const blockBlobClient = containerClient.getBlockBlobClient(blobName);
188
- const downloadBlockBlobResponse = await blockBlobClient.download(0);
196
+ const expression = (options == null ? void 0 : options.range) || "";
197
+ const matches = expression.match(/\d+/g);
198
+ if (expression && (matches == null ? void 0 : matches.length)) {
199
+ const [start, end] = matches.map(Number);
200
+ downloadBlockBlobResponse = await blockBlobClient.download(
201
+ start,
202
+ end
203
+ );
204
+ } else {
205
+ downloadBlockBlobResponse = await blockBlobClient.download(0);
206
+ }
189
207
  return {
190
208
  body: downloadBlockBlobResponse.readableStreamBody,
191
209
  metadata: downloadBlockBlobResponse.metadata,
@@ -447,6 +465,71 @@ var BlobStorageService = class {
447
465
  );
448
466
  }
449
467
  }
468
+ async listMultipartUploadsForBucket() {
469
+ const containerClient = this.blobServiceClient.getContainerClient(
470
+ this.containerName
471
+ );
472
+ const blobList = containerClient.listBlobsFlat();
473
+ const uploads = [];
474
+ try {
475
+ for (var iter = __forAwait(blobList), more, temp, error; more = !(temp = await iter.next()).done; more = false) {
476
+ const blob = temp.value;
477
+ uploads.push({
478
+ uploadId: blob.name,
479
+ key: blob.name,
480
+ initiated: blob.properties.createdOn || /* @__PURE__ */ new Date()
481
+ });
482
+ }
483
+ } catch (temp) {
484
+ error = [temp];
485
+ } finally {
486
+ try {
487
+ more && (temp = iter.return) && await temp.call(iter);
488
+ } finally {
489
+ if (error)
490
+ throw error[0];
491
+ }
492
+ }
493
+ return {
494
+ bucketName: this.containerName,
495
+ uploads
496
+ };
497
+ }
498
+ /**
499
+ * Retrieves the list of parts for a multipart upload.
500
+ *
501
+ * @param {string} blobName - The name of the blob (file) in Azure Blob Storage.
502
+ * @return {Promise<ListPartsMultipartUploadResponse>} A promise that resolves to the list of parts for the multipart upload.
503
+ */
504
+ async listMultipartUploadsForKey(blobName) {
505
+ var _a;
506
+ const containerClient = this.blobServiceClient.getContainerClient(
507
+ this.containerName
508
+ );
509
+ const blobClient = containerClient.getBlockBlobClient(blobName);
510
+ const listResponse = await blobClient.getBlockList("all");
511
+ const parts = ((_a = listResponse == null ? void 0 : listResponse.uncommittedBlocks) == null ? void 0 : _a.map((block, index) => ({
512
+ PartNumber: index + 1,
513
+ LastModified: /* @__PURE__ */ new Date(),
514
+ // Azure Blob Storage doesn't provide the last modified date for individual parts
515
+ ETag: block.name,
516
+ Size: block.size
517
+ }))) || [];
518
+ return {
519
+ Parts: parts
520
+ };
521
+ }
522
+ /**
523
+ * Generates a unique upload ID for multipart uploads.
524
+ *
525
+ * @return {Promise<string>} A promise that resolves to a unique upload ID.
526
+ */
527
+ async generateUploadIdMultipart() {
528
+ const timestamp = Date.now();
529
+ const randomNum = Math.floor(Math.random() * 100);
530
+ const blockIdBase = (timestamp - randomNum).toString();
531
+ return blockIdBase;
532
+ }
450
533
  /**
451
534
  * Uploads a part of a file as a block to Azure Blob Storage and updates the metadata with the block ID.
452
535
  *
@@ -461,17 +544,10 @@ var BlobStorageService = class {
461
544
  this.containerName
462
545
  );
463
546
  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
- }
547
+ const blockIdBase = uploadId || await this.generateUploadIdMultipart();
470
548
  const partId = partNumber.toString().padStart(6, "0");
471
549
  const partIdBase64 = Buffer.from(partId).toString("base64");
472
550
  await blobClient.stageBlock(partIdBase64, file, file.length);
473
- const blockIdStorage = BlockIdStorage.getInstance();
474
- blockIdStorage.addBlockId(blockIdBase, partIdBase64);
475
551
  return blockIdBase;
476
552
  }
477
553
  /**
@@ -483,17 +559,17 @@ var BlobStorageService = class {
483
559
  * @throws {Error} If no block IDs are found in the metadata.
484
560
  */
485
561
  async completeMultipartUpload(blobName, uploadId) {
562
+ var _a;
486
563
  const containerClient = this.blobServiceClient.getContainerClient(
487
564
  this.containerName
488
565
  );
489
566
  const blobClient = containerClient.getBlockBlobClient(blobName);
490
- const blockIdStorage = BlockIdStorage.getInstance();
491
- const blockIds = blockIdStorage.getBlockIds(uploadId);
567
+ const listMultipartUploads = await this.listMultipartUploadsForKey(blobName);
568
+ const blockIds = ((_a = listMultipartUploads == null ? void 0 : listMultipartUploads.Parts) == null ? void 0 : _a.map((part) => part.ETag)) || [];
492
569
  if (blockIds.length === 0) {
493
570
  throw new Error("No block IDs found in metadata.");
494
571
  }
495
572
  await blobClient.commitBlockList(blockIds);
496
- blockIdStorage.clearBlockIds(uploadId);
497
573
  }
498
574
  /**
499
575
  * Aborts a multipart upload by deleting the specified blob and clearing its block IDs metadata.
@@ -511,6 +587,17 @@ var BlobStorageService = class {
511
587
  blockIdStorage.clearBlockIds(uploadId);
512
588
  await blobClient.delete();
513
589
  }
590
+ async getMultipartUploadPresignedUrl(blobName, uploadId, partNumber, expiresInMinutes = 2) {
591
+ const partId = partNumber.toString().padStart(6, "0");
592
+ const partIdBase64 = Buffer.from(partId).toString("base64");
593
+ const sasUrl = await this.getSignatureUrl(
594
+ blobName,
595
+ expiresInMinutes,
596
+ "w"
597
+ );
598
+ const url = `${sasUrl}&comp=block&blockid=${partIdBase64}`;
599
+ return url;
600
+ }
514
601
  };
515
602
 
516
603
  // src/services/storage/s3/s3Helpers.ts
@@ -767,18 +854,69 @@ var S3StorageService = class {
767
854
  );
768
855
  }
769
856
  }
857
+ /**
858
+ * Generates an upload ID for multipart upload in the S3 bucket.
859
+ *
860
+ * @param {string} key - The key of the object to upload.
861
+ * @return {Promise<string>} A promise that resolves to the generated upload ID.
862
+ * @throws {Error} If no upload ID was generated.
863
+ */
864
+ async generateUploadIdMultipart(key) {
865
+ const params = {
866
+ Bucket: this.bucketName,
867
+ Key: key
868
+ };
869
+ const response = await this.s3.createMultipartUpload(params);
870
+ if (!(response == null ? void 0 : response.UploadId))
871
+ throw new Error("No upload ID was generated");
872
+ return response.UploadId;
873
+ }
874
+ async listMultipartUploadsForBucket() {
875
+ const params = {
876
+ Bucket: this.bucketName
877
+ };
878
+ const response = await this.s3.listMultipartUploads(params);
879
+ return {
880
+ bucketName: this.bucketName,
881
+ uploads: response.Uploads ? response.Uploads.map((upload) => {
882
+ var _a, _b;
883
+ return {
884
+ uploadId: upload.UploadId || "",
885
+ key: upload.Key || "",
886
+ initiator: ((_a = upload == null ? void 0 : upload.Initiator) == null ? void 0 : _a.ID) || "",
887
+ owner: ((_b = upload == null ? void 0 : upload.Owner) == null ? void 0 : _b.ID) || "",
888
+ storageClass: upload.StorageClass || "",
889
+ initiated: upload.Initiated || ""
890
+ };
891
+ }) : []
892
+ };
893
+ }
894
+ /**
895
+ * Retrieves the list of parts for a multipart upload.
896
+ *
897
+ * @param {string} key - The key of the object being uploaded.
898
+ * @param {string} uploadId - The ID of the multipart upload.
899
+ * @return {Promise<ListPartsMultipartUploadResponse>} A promise that resolves to the list of parts for the multipart upload.
900
+ */
901
+ async listMultipartUploadsForKey(key, uploadId) {
902
+ const params = {
903
+ Bucket: this.bucketName,
904
+ Key: key,
905
+ UploadId: uploadId
906
+ };
907
+ const response = await this.s3.listParts(params);
908
+ const parts = response.Parts ? response.Parts.map((part) => ({
909
+ PartNumber: part.PartNumber,
910
+ LastModified: part.LastModified,
911
+ ETag: part.ETag,
912
+ Size: part.Size
913
+ })) : [];
914
+ return {
915
+ Parts: parts
916
+ };
917
+ }
770
918
  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
- }
919
+ const upId = uploadId || await this.generateUploadIdMultipart(key);
782
920
  const params = {
783
921
  Bucket: this.bucketName,
784
922
  Key: key,
@@ -790,12 +928,10 @@ var S3StorageService = class {
790
928
  return upId;
791
929
  }
792
930
  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);
931
+ const partsResponse = await this.listMultipartUploadsForKey(
932
+ key,
933
+ uploadId
934
+ );
799
935
  const partsList = (partsResponse == null ? void 0 : partsResponse.Parts) && partsResponse.Parts.map(
800
936
  // eslint-disable-next-line no-unused-vars, @typescript-eslint/no-unused-vars
801
937
  (_a) => {
@@ -803,11 +939,14 @@ var S3StorageService = class {
803
939
  return partList;
804
940
  }
805
941
  );
806
- const completeMultipartParams = __spreadProps(__spreadValues({}, listPartsParams), {
942
+ const completeMultipartParams = {
943
+ Bucket: this.bucketName,
944
+ Key: key,
945
+ UploadId: uploadId,
807
946
  MultipartUpload: {
808
947
  Parts: partsList
809
948
  }
810
- });
949
+ };
811
950
  await this.s3.completeMultipartUpload(completeMultipartParams);
812
951
  }
813
952
  async abortMultipartUpload(key, uploadId) {
@@ -818,6 +957,21 @@ var S3StorageService = class {
818
957
  };
819
958
  await this.s3.abortMultipartUpload(params);
820
959
  }
960
+ async getMultipartUploadPresignedUrl(key, uploadId, partNumber, expiresInMinutes = 60) {
961
+ const uploadPartParams = {
962
+ Bucket: this.bucketName,
963
+ Key: key,
964
+ UploadId: uploadId,
965
+ PartNumber: parseInt(partNumber, 10)
966
+ };
967
+ const expiresIn = expiresInMinutes * 60;
968
+ const presignedUrl = await getSignedUrl(
969
+ this.s3Client,
970
+ new UploadPartCommand(uploadPartParams),
971
+ { expiresIn }
972
+ );
973
+ return presignedUrl;
974
+ }
821
975
  };
822
976
 
823
977
  // src/shared/utils/constants.ts
@@ -887,10 +1041,10 @@ var ObjectStorageService = class _ObjectStorageService {
887
1041
  * @param {string} [bucketName] - The name of the bucket where the object is stored. If not provided, the default bucket name will be used.
888
1042
  * @return {Promise<GetObjectResponse>} A promise that resolves to the retrieved object.
889
1043
  */
890
- static async getObject(key, bucketName) {
1044
+ static async getObject(key, bucketName, options) {
891
1045
  return _ObjectStorageService.getObjectStorageServiceInstance(
892
1046
  bucketName
893
- ).then((instance) => instance.getObject(key));
1047
+ ).then((instance) => instance.getObject(key, options));
894
1048
  }
895
1049
  /**
896
1050
  * Retrieves an object info (without file content) from the object storage service.
@@ -996,6 +1150,44 @@ var ObjectStorageService = class _ObjectStorageService {
996
1150
  bucketName
997
1151
  ).then((instance) => instance.getHeadBucket());
998
1152
  }
1153
+ /**
1154
+ * Generates a unique upload ID for a multipart upload.
1155
+ *
1156
+ * @param {string} key - The key of the object to upload.
1157
+ * @param {string} [bucketName] - The name of the bucket. If not provided, the default bucket name will be used.
1158
+ * @return {Promise<string>} A promise that resolves to the generated upload ID.
1159
+ */
1160
+ static async generateUploadIdMultipart(key, bucketName) {
1161
+ return _ObjectStorageService.getObjectStorageServiceInstance(
1162
+ bucketName
1163
+ ).then((instance) => instance.generateUploadIdMultipart(key));
1164
+ }
1165
+ /**
1166
+ * Retrieves a list of multipart uploads for a specified key in the object storage service.
1167
+ *
1168
+ * @param {string} key - The key of the object to retrieve uploads for.
1169
+ * @param {string} [bucketName] - The name of the bucket. If not provided, the default bucket name will be used.
1170
+ * @param {string} [uploadId] - The upload ID to filter the results by.
1171
+ * @return {Promise<ListPartsMultipartUploadResponse>} A promise that resolves to the list of multipart uploads for the specified key.
1172
+ */
1173
+ static async listMultipartUploadsForKey(key, bucketName, uploadId) {
1174
+ return _ObjectStorageService.getObjectStorageServiceInstance(
1175
+ bucketName
1176
+ ).then(
1177
+ (instance) => instance.listMultipartUploadsForKey(key, uploadId)
1178
+ );
1179
+ }
1180
+ /**
1181
+ * Retrieves a list of all multipart uploads for a specified bucket in the object storage service.
1182
+ *
1183
+ * @param {string} [bucketName] - The name of the bucket. If not provided, the default bucket name will be used.
1184
+ * @return {Promise<ListMultipartUploadsResponse>} A promise that resolves to the list of multipart uploads for the specified bucket.
1185
+ */
1186
+ static async listMultipartUploadsForBucket(bucketName) {
1187
+ return _ObjectStorageService.getObjectStorageServiceInstance(
1188
+ bucketName
1189
+ ).then((instance) => instance.listMultipartUploadsForBucket());
1190
+ }
999
1191
  /**
1000
1192
  * Uploads a multipart file to the specified bucket in the object storage service.
1001
1193
  *
@@ -1039,6 +1231,25 @@ var ObjectStorageService = class _ObjectStorageService {
1039
1231
  bucketName
1040
1232
  ).then((instance) => instance.abortMultipartUpload(key, uploadId));
1041
1233
  }
1234
+ /**
1235
+ * Retrieves a presigned URL for a specific part of a multipart upload.
1236
+ *
1237
+ * @param {string} key - The key of the object for which to generate the presigned URL.
1238
+ * @param {string} uploadId - The ID of the multipart upload.
1239
+ * @param {string} partNumber - The number of the part for which to generate the presigned URL.
1240
+ * @param {number} [expiresInMinutes] - The number of minutes until the presigned URL expires. Default is 60 minutes.
1241
+ * @return {Promise<string>} A Promise that resolves to the presigned URL for the specified part of the multipart upload.
1242
+ */
1243
+ static async getMultipartUploadPresignedUrl(key, uploadId, partNumber, expiresInMinutes) {
1244
+ return _ObjectStorageService.getObjectStorageServiceInstance().then(
1245
+ (instance) => instance.getMultipartUploadPresignedUrl(
1246
+ key,
1247
+ uploadId,
1248
+ partNumber,
1249
+ expiresInMinutes
1250
+ )
1251
+ );
1252
+ }
1042
1253
  };
1043
1254
 
1044
1255
  export { ObjectStorageService };