@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.
- package/README.md +1 -1
- package/dist/cjs/index.js +245 -34
- package/dist/cjs/index.js.map +1 -1
- package/dist/esm/index.d.mts +79 -2
- package/dist/esm/index.mjs +246 -35
- package/dist/esm/index.mjs.map +1 -1
- package/dist/types/index.d.ts +79 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# @qrvey/object-storage
|
|
2
2
|
|
|
3
3
|

|
|
4
|
-

|
|
5
5
|
|
|
6
6
|
The `@qrvey/object-storage` package provides a unified interface for ...
|
|
7
7
|
|
package/dist/cjs/index.js
CHANGED
|
@@ -16,6 +16,11 @@ var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
|
|
|
16
16
|
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
|
|
17
17
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
18
18
|
var __propIsEnum = Object.prototype.propertyIsEnumerable;
|
|
19
|
+
var __knownSymbol = (name, symbol) => {
|
|
20
|
+
if (symbol = Symbol[name])
|
|
21
|
+
return symbol;
|
|
22
|
+
throw Error("Symbol." + name + " is not defined");
|
|
23
|
+
};
|
|
19
24
|
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
20
25
|
var __spreadValues = (a, b) => {
|
|
21
26
|
for (var prop in b || (b = {}))
|
|
@@ -41,6 +46,7 @@ var __objRest = (source, exclude) => {
|
|
|
41
46
|
}
|
|
42
47
|
return target;
|
|
43
48
|
};
|
|
49
|
+
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);
|
|
44
50
|
|
|
45
51
|
// src/shared/utils/errorHandler.ts
|
|
46
52
|
var errorMessages = {
|
|
@@ -182,16 +188,28 @@ var BlobStorageService = class {
|
|
|
182
188
|
* Retrieves an object from the blob storage service.
|
|
183
189
|
*
|
|
184
190
|
* @param {string} blobName - The name of the blob to retrieve.
|
|
191
|
+
* @param {Object} [options] - The options that you can pass to the library.
|
|
185
192
|
* @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.
|
|
186
193
|
*/
|
|
187
|
-
async getObject(blobName) {
|
|
194
|
+
async getObject(blobName, options) {
|
|
188
195
|
var _a;
|
|
189
196
|
try {
|
|
197
|
+
let downloadBlockBlobResponse;
|
|
190
198
|
const containerClient = this.blobServiceClient.getContainerClient(
|
|
191
199
|
this.containerName
|
|
192
200
|
);
|
|
193
201
|
const blockBlobClient = containerClient.getBlockBlobClient(blobName);
|
|
194
|
-
const
|
|
202
|
+
const expression = (options == null ? void 0 : options.range) || "";
|
|
203
|
+
const matches = expression.match(/\d+/g);
|
|
204
|
+
if (expression && (matches == null ? void 0 : matches.length)) {
|
|
205
|
+
const [start, end] = matches.map(Number);
|
|
206
|
+
downloadBlockBlobResponse = await blockBlobClient.download(
|
|
207
|
+
start,
|
|
208
|
+
end
|
|
209
|
+
);
|
|
210
|
+
} else {
|
|
211
|
+
downloadBlockBlobResponse = await blockBlobClient.download(0);
|
|
212
|
+
}
|
|
195
213
|
return {
|
|
196
214
|
body: downloadBlockBlobResponse.readableStreamBody,
|
|
197
215
|
metadata: downloadBlockBlobResponse.metadata,
|
|
@@ -453,6 +471,71 @@ var BlobStorageService = class {
|
|
|
453
471
|
);
|
|
454
472
|
}
|
|
455
473
|
}
|
|
474
|
+
async listMultipartUploadsForBucket() {
|
|
475
|
+
const containerClient = this.blobServiceClient.getContainerClient(
|
|
476
|
+
this.containerName
|
|
477
|
+
);
|
|
478
|
+
const blobList = containerClient.listBlobsFlat();
|
|
479
|
+
const uploads = [];
|
|
480
|
+
try {
|
|
481
|
+
for (var iter = __forAwait(blobList), more, temp, error; more = !(temp = await iter.next()).done; more = false) {
|
|
482
|
+
const blob = temp.value;
|
|
483
|
+
uploads.push({
|
|
484
|
+
uploadId: blob.name,
|
|
485
|
+
key: blob.name,
|
|
486
|
+
initiated: blob.properties.createdOn || /* @__PURE__ */ new Date()
|
|
487
|
+
});
|
|
488
|
+
}
|
|
489
|
+
} catch (temp) {
|
|
490
|
+
error = [temp];
|
|
491
|
+
} finally {
|
|
492
|
+
try {
|
|
493
|
+
more && (temp = iter.return) && await temp.call(iter);
|
|
494
|
+
} finally {
|
|
495
|
+
if (error)
|
|
496
|
+
throw error[0];
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
return {
|
|
500
|
+
bucketName: this.containerName,
|
|
501
|
+
uploads
|
|
502
|
+
};
|
|
503
|
+
}
|
|
504
|
+
/**
|
|
505
|
+
* Retrieves the list of parts for a multipart upload.
|
|
506
|
+
*
|
|
507
|
+
* @param {string} blobName - The name of the blob (file) in Azure Blob Storage.
|
|
508
|
+
* @return {Promise<ListPartsMultipartUploadResponse>} A promise that resolves to the list of parts for the multipart upload.
|
|
509
|
+
*/
|
|
510
|
+
async listMultipartUploadsForKey(blobName) {
|
|
511
|
+
var _a;
|
|
512
|
+
const containerClient = this.blobServiceClient.getContainerClient(
|
|
513
|
+
this.containerName
|
|
514
|
+
);
|
|
515
|
+
const blobClient = containerClient.getBlockBlobClient(blobName);
|
|
516
|
+
const listResponse = await blobClient.getBlockList("all");
|
|
517
|
+
const parts = ((_a = listResponse == null ? void 0 : listResponse.uncommittedBlocks) == null ? void 0 : _a.map((block, index) => ({
|
|
518
|
+
PartNumber: index + 1,
|
|
519
|
+
LastModified: /* @__PURE__ */ new Date(),
|
|
520
|
+
// Azure Blob Storage doesn't provide the last modified date for individual parts
|
|
521
|
+
ETag: block.name,
|
|
522
|
+
Size: block.size
|
|
523
|
+
}))) || [];
|
|
524
|
+
return {
|
|
525
|
+
Parts: parts
|
|
526
|
+
};
|
|
527
|
+
}
|
|
528
|
+
/**
|
|
529
|
+
* Generates a unique upload ID for multipart uploads.
|
|
530
|
+
*
|
|
531
|
+
* @return {Promise<string>} A promise that resolves to a unique upload ID.
|
|
532
|
+
*/
|
|
533
|
+
async generateUploadIdMultipart() {
|
|
534
|
+
const timestamp = Date.now();
|
|
535
|
+
const randomNum = Math.floor(Math.random() * 100);
|
|
536
|
+
const blockIdBase = (timestamp - randomNum).toString();
|
|
537
|
+
return blockIdBase;
|
|
538
|
+
}
|
|
456
539
|
/**
|
|
457
540
|
* Uploads a part of a file as a block to Azure Blob Storage and updates the metadata with the block ID.
|
|
458
541
|
*
|
|
@@ -467,17 +550,10 @@ var BlobStorageService = class {
|
|
|
467
550
|
this.containerName
|
|
468
551
|
);
|
|
469
552
|
const blobClient = containerClient.getBlockBlobClient(blobName);
|
|
470
|
-
|
|
471
|
-
if (!blockIdBase) {
|
|
472
|
-
const timestamp = Date.now();
|
|
473
|
-
const randomNum = Math.floor(Math.random() * 100);
|
|
474
|
-
blockIdBase = (timestamp - randomNum).toString();
|
|
475
|
-
}
|
|
553
|
+
const blockIdBase = uploadId || await this.generateUploadIdMultipart();
|
|
476
554
|
const partId = partNumber.toString().padStart(6, "0");
|
|
477
555
|
const partIdBase64 = Buffer.from(partId).toString("base64");
|
|
478
556
|
await blobClient.stageBlock(partIdBase64, file, file.length);
|
|
479
|
-
const blockIdStorage = BlockIdStorage.getInstance();
|
|
480
|
-
blockIdStorage.addBlockId(blockIdBase, partIdBase64);
|
|
481
557
|
return blockIdBase;
|
|
482
558
|
}
|
|
483
559
|
/**
|
|
@@ -489,17 +565,17 @@ var BlobStorageService = class {
|
|
|
489
565
|
* @throws {Error} If no block IDs are found in the metadata.
|
|
490
566
|
*/
|
|
491
567
|
async completeMultipartUpload(blobName, uploadId) {
|
|
568
|
+
var _a;
|
|
492
569
|
const containerClient = this.blobServiceClient.getContainerClient(
|
|
493
570
|
this.containerName
|
|
494
571
|
);
|
|
495
572
|
const blobClient = containerClient.getBlockBlobClient(blobName);
|
|
496
|
-
const
|
|
497
|
-
const blockIds =
|
|
573
|
+
const listMultipartUploads = await this.listMultipartUploadsForKey(blobName);
|
|
574
|
+
const blockIds = ((_a = listMultipartUploads == null ? void 0 : listMultipartUploads.Parts) == null ? void 0 : _a.map((part) => part.ETag)) || [];
|
|
498
575
|
if (blockIds.length === 0) {
|
|
499
576
|
throw new Error("No block IDs found in metadata.");
|
|
500
577
|
}
|
|
501
578
|
await blobClient.commitBlockList(blockIds);
|
|
502
|
-
blockIdStorage.clearBlockIds(uploadId);
|
|
503
579
|
}
|
|
504
580
|
/**
|
|
505
581
|
* Aborts a multipart upload by deleting the specified blob and clearing its block IDs metadata.
|
|
@@ -517,6 +593,17 @@ var BlobStorageService = class {
|
|
|
517
593
|
blockIdStorage.clearBlockIds(uploadId);
|
|
518
594
|
await blobClient.delete();
|
|
519
595
|
}
|
|
596
|
+
async getMultipartUploadPresignedUrl(blobName, uploadId, partNumber, expiresInMinutes = 2) {
|
|
597
|
+
const partId = partNumber.toString().padStart(6, "0");
|
|
598
|
+
const partIdBase64 = Buffer.from(partId).toString("base64");
|
|
599
|
+
const sasUrl = await this.getSignatureUrl(
|
|
600
|
+
blobName,
|
|
601
|
+
expiresInMinutes,
|
|
602
|
+
"w"
|
|
603
|
+
);
|
|
604
|
+
const url = `${sasUrl}&comp=block&blockid=${partIdBase64}`;
|
|
605
|
+
return url;
|
|
606
|
+
}
|
|
520
607
|
};
|
|
521
608
|
|
|
522
609
|
// src/services/storage/s3/s3Helpers.ts
|
|
@@ -773,18 +860,69 @@ var S3StorageService = class {
|
|
|
773
860
|
);
|
|
774
861
|
}
|
|
775
862
|
}
|
|
863
|
+
/**
|
|
864
|
+
* Generates an upload ID for multipart upload in the S3 bucket.
|
|
865
|
+
*
|
|
866
|
+
* @param {string} key - The key of the object to upload.
|
|
867
|
+
* @return {Promise<string>} A promise that resolves to the generated upload ID.
|
|
868
|
+
* @throws {Error} If no upload ID was generated.
|
|
869
|
+
*/
|
|
870
|
+
async generateUploadIdMultipart(key) {
|
|
871
|
+
const params = {
|
|
872
|
+
Bucket: this.bucketName,
|
|
873
|
+
Key: key
|
|
874
|
+
};
|
|
875
|
+
const response = await this.s3.createMultipartUpload(params);
|
|
876
|
+
if (!(response == null ? void 0 : response.UploadId))
|
|
877
|
+
throw new Error("No upload ID was generated");
|
|
878
|
+
return response.UploadId;
|
|
879
|
+
}
|
|
880
|
+
async listMultipartUploadsForBucket() {
|
|
881
|
+
const params = {
|
|
882
|
+
Bucket: this.bucketName
|
|
883
|
+
};
|
|
884
|
+
const response = await this.s3.listMultipartUploads(params);
|
|
885
|
+
return {
|
|
886
|
+
bucketName: this.bucketName,
|
|
887
|
+
uploads: response.Uploads ? response.Uploads.map((upload) => {
|
|
888
|
+
var _a, _b;
|
|
889
|
+
return {
|
|
890
|
+
uploadId: upload.UploadId || "",
|
|
891
|
+
key: upload.Key || "",
|
|
892
|
+
initiator: ((_a = upload == null ? void 0 : upload.Initiator) == null ? void 0 : _a.ID) || "",
|
|
893
|
+
owner: ((_b = upload == null ? void 0 : upload.Owner) == null ? void 0 : _b.ID) || "",
|
|
894
|
+
storageClass: upload.StorageClass || "",
|
|
895
|
+
initiated: upload.Initiated || ""
|
|
896
|
+
};
|
|
897
|
+
}) : []
|
|
898
|
+
};
|
|
899
|
+
}
|
|
900
|
+
/**
|
|
901
|
+
* Retrieves the list of parts for a multipart upload.
|
|
902
|
+
*
|
|
903
|
+
* @param {string} key - The key of the object being uploaded.
|
|
904
|
+
* @param {string} uploadId - The ID of the multipart upload.
|
|
905
|
+
* @return {Promise<ListPartsMultipartUploadResponse>} A promise that resolves to the list of parts for the multipart upload.
|
|
906
|
+
*/
|
|
907
|
+
async listMultipartUploadsForKey(key, uploadId) {
|
|
908
|
+
const params = {
|
|
909
|
+
Bucket: this.bucketName,
|
|
910
|
+
Key: key,
|
|
911
|
+
UploadId: uploadId
|
|
912
|
+
};
|
|
913
|
+
const response = await this.s3.listParts(params);
|
|
914
|
+
const parts = response.Parts ? response.Parts.map((part) => ({
|
|
915
|
+
PartNumber: part.PartNumber,
|
|
916
|
+
LastModified: part.LastModified,
|
|
917
|
+
ETag: part.ETag,
|
|
918
|
+
Size: part.Size
|
|
919
|
+
})) : [];
|
|
920
|
+
return {
|
|
921
|
+
Parts: parts
|
|
922
|
+
};
|
|
923
|
+
}
|
|
776
924
|
async uploadMultipart(key, file, partNumber, uploadId) {
|
|
777
|
-
|
|
778
|
-
if (!upId) {
|
|
779
|
-
const params2 = {
|
|
780
|
-
Bucket: this.bucketName,
|
|
781
|
-
Key: key
|
|
782
|
-
};
|
|
783
|
-
const response = await this.s3.createMultipartUpload(params2);
|
|
784
|
-
if (!(response == null ? void 0 : response.UploadId))
|
|
785
|
-
throw new Error("No upload ID was generated");
|
|
786
|
-
upId = response.UploadId;
|
|
787
|
-
}
|
|
925
|
+
const upId = uploadId || await this.generateUploadIdMultipart(key);
|
|
788
926
|
const params = {
|
|
789
927
|
Bucket: this.bucketName,
|
|
790
928
|
Key: key,
|
|
@@ -796,12 +934,10 @@ var S3StorageService = class {
|
|
|
796
934
|
return upId;
|
|
797
935
|
}
|
|
798
936
|
async completeMultipartUpload(key, uploadId) {
|
|
799
|
-
const
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
};
|
|
804
|
-
const partsResponse = await this.s3.listParts(listPartsParams);
|
|
937
|
+
const partsResponse = await this.listMultipartUploadsForKey(
|
|
938
|
+
key,
|
|
939
|
+
uploadId
|
|
940
|
+
);
|
|
805
941
|
const partsList = (partsResponse == null ? void 0 : partsResponse.Parts) && partsResponse.Parts.map(
|
|
806
942
|
// eslint-disable-next-line no-unused-vars, @typescript-eslint/no-unused-vars
|
|
807
943
|
(_a) => {
|
|
@@ -809,11 +945,14 @@ var S3StorageService = class {
|
|
|
809
945
|
return partList;
|
|
810
946
|
}
|
|
811
947
|
);
|
|
812
|
-
const completeMultipartParams =
|
|
948
|
+
const completeMultipartParams = {
|
|
949
|
+
Bucket: this.bucketName,
|
|
950
|
+
Key: key,
|
|
951
|
+
UploadId: uploadId,
|
|
813
952
|
MultipartUpload: {
|
|
814
953
|
Parts: partsList
|
|
815
954
|
}
|
|
816
|
-
}
|
|
955
|
+
};
|
|
817
956
|
await this.s3.completeMultipartUpload(completeMultipartParams);
|
|
818
957
|
}
|
|
819
958
|
async abortMultipartUpload(key, uploadId) {
|
|
@@ -824,6 +963,21 @@ var S3StorageService = class {
|
|
|
824
963
|
};
|
|
825
964
|
await this.s3.abortMultipartUpload(params);
|
|
826
965
|
}
|
|
966
|
+
async getMultipartUploadPresignedUrl(key, uploadId, partNumber, expiresInMinutes = 60) {
|
|
967
|
+
const uploadPartParams = {
|
|
968
|
+
Bucket: this.bucketName,
|
|
969
|
+
Key: key,
|
|
970
|
+
UploadId: uploadId,
|
|
971
|
+
PartNumber: parseInt(partNumber, 10)
|
|
972
|
+
};
|
|
973
|
+
const expiresIn = expiresInMinutes * 60;
|
|
974
|
+
const presignedUrl = await s3RequestPresigner.getSignedUrl(
|
|
975
|
+
this.s3Client,
|
|
976
|
+
new clientS3.UploadPartCommand(uploadPartParams),
|
|
977
|
+
{ expiresIn }
|
|
978
|
+
);
|
|
979
|
+
return presignedUrl;
|
|
980
|
+
}
|
|
827
981
|
};
|
|
828
982
|
|
|
829
983
|
// src/shared/utils/constants.ts
|
|
@@ -893,10 +1047,10 @@ var ObjectStorageService = class _ObjectStorageService {
|
|
|
893
1047
|
* @param {string} [bucketName] - The name of the bucket where the object is stored. If not provided, the default bucket name will be used.
|
|
894
1048
|
* @return {Promise<GetObjectResponse>} A promise that resolves to the retrieved object.
|
|
895
1049
|
*/
|
|
896
|
-
static async getObject(key, bucketName) {
|
|
1050
|
+
static async getObject(key, bucketName, options) {
|
|
897
1051
|
return _ObjectStorageService.getObjectStorageServiceInstance(
|
|
898
1052
|
bucketName
|
|
899
|
-
).then((instance) => instance.getObject(key));
|
|
1053
|
+
).then((instance) => instance.getObject(key, options));
|
|
900
1054
|
}
|
|
901
1055
|
/**
|
|
902
1056
|
* Retrieves an object info (without file content) from the object storage service.
|
|
@@ -1002,6 +1156,44 @@ var ObjectStorageService = class _ObjectStorageService {
|
|
|
1002
1156
|
bucketName
|
|
1003
1157
|
).then((instance) => instance.getHeadBucket());
|
|
1004
1158
|
}
|
|
1159
|
+
/**
|
|
1160
|
+
* Generates a unique upload ID for a multipart upload.
|
|
1161
|
+
*
|
|
1162
|
+
* @param {string} key - The key of the object to upload.
|
|
1163
|
+
* @param {string} [bucketName] - The name of the bucket. If not provided, the default bucket name will be used.
|
|
1164
|
+
* @return {Promise<string>} A promise that resolves to the generated upload ID.
|
|
1165
|
+
*/
|
|
1166
|
+
static async generateUploadIdMultipart(key, bucketName) {
|
|
1167
|
+
return _ObjectStorageService.getObjectStorageServiceInstance(
|
|
1168
|
+
bucketName
|
|
1169
|
+
).then((instance) => instance.generateUploadIdMultipart(key));
|
|
1170
|
+
}
|
|
1171
|
+
/**
|
|
1172
|
+
* Retrieves a list of multipart uploads for a specified key in the object storage service.
|
|
1173
|
+
*
|
|
1174
|
+
* @param {string} key - The key of the object to retrieve uploads for.
|
|
1175
|
+
* @param {string} [bucketName] - The name of the bucket. If not provided, the default bucket name will be used.
|
|
1176
|
+
* @param {string} [uploadId] - The upload ID to filter the results by.
|
|
1177
|
+
* @return {Promise<ListPartsMultipartUploadResponse>} A promise that resolves to the list of multipart uploads for the specified key.
|
|
1178
|
+
*/
|
|
1179
|
+
static async listMultipartUploadsForKey(key, bucketName, uploadId) {
|
|
1180
|
+
return _ObjectStorageService.getObjectStorageServiceInstance(
|
|
1181
|
+
bucketName
|
|
1182
|
+
).then(
|
|
1183
|
+
(instance) => instance.listMultipartUploadsForKey(key, uploadId)
|
|
1184
|
+
);
|
|
1185
|
+
}
|
|
1186
|
+
/**
|
|
1187
|
+
* Retrieves a list of all multipart uploads for a specified bucket in the object storage service.
|
|
1188
|
+
*
|
|
1189
|
+
* @param {string} [bucketName] - The name of the bucket. If not provided, the default bucket name will be used.
|
|
1190
|
+
* @return {Promise<ListMultipartUploadsResponse>} A promise that resolves to the list of multipart uploads for the specified bucket.
|
|
1191
|
+
*/
|
|
1192
|
+
static async listMultipartUploadsForBucket(bucketName) {
|
|
1193
|
+
return _ObjectStorageService.getObjectStorageServiceInstance(
|
|
1194
|
+
bucketName
|
|
1195
|
+
).then((instance) => instance.listMultipartUploadsForBucket());
|
|
1196
|
+
}
|
|
1005
1197
|
/**
|
|
1006
1198
|
* Uploads a multipart file to the specified bucket in the object storage service.
|
|
1007
1199
|
*
|
|
@@ -1045,6 +1237,25 @@ var ObjectStorageService = class _ObjectStorageService {
|
|
|
1045
1237
|
bucketName
|
|
1046
1238
|
).then((instance) => instance.abortMultipartUpload(key, uploadId));
|
|
1047
1239
|
}
|
|
1240
|
+
/**
|
|
1241
|
+
* Retrieves a presigned URL for a specific part of a multipart upload.
|
|
1242
|
+
*
|
|
1243
|
+
* @param {string} key - The key of the object for which to generate the presigned URL.
|
|
1244
|
+
* @param {string} uploadId - The ID of the multipart upload.
|
|
1245
|
+
* @param {string} partNumber - The number of the part for which to generate the presigned URL.
|
|
1246
|
+
* @param {number} [expiresInMinutes] - The number of minutes until the presigned URL expires. Default is 60 minutes.
|
|
1247
|
+
* @return {Promise<string>} A Promise that resolves to the presigned URL for the specified part of the multipart upload.
|
|
1248
|
+
*/
|
|
1249
|
+
static async getMultipartUploadPresignedUrl(key, uploadId, partNumber, expiresInMinutes) {
|
|
1250
|
+
return _ObjectStorageService.getObjectStorageServiceInstance().then(
|
|
1251
|
+
(instance) => instance.getMultipartUploadPresignedUrl(
|
|
1252
|
+
key,
|
|
1253
|
+
uploadId,
|
|
1254
|
+
partNumber,
|
|
1255
|
+
expiresInMinutes
|
|
1256
|
+
)
|
|
1257
|
+
);
|
|
1258
|
+
}
|
|
1048
1259
|
};
|
|
1049
1260
|
|
|
1050
1261
|
exports.ObjectStorageService = ObjectStorageService;
|