@lossless.org/client 0.1.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.
- package/.smartconfig.json +37 -0
- package/dist_ts/00_commitinfo_data.d.ts +8 -0
- package/dist_ts/00_commitinfo_data.js +9 -0
- package/dist_ts/classes.losslessorgclient.d.ts +32 -0
- package/dist_ts/classes.losslessorgclient.js +103 -0
- package/dist_ts/core/classes.error.d.ts +16 -0
- package/dist_ts/core/classes.error.js +29 -0
- package/dist_ts/core/classes.operation.d.ts +17 -0
- package/dist_ts/core/classes.operation.js +70 -0
- package/dist_ts/core/interfaces.d.ts +18 -0
- package/dist_ts/core/interfaces.js +2 -0
- package/dist_ts/index.d.ts +4 -0
- package/dist_ts/index.js +3 -0
- package/dist_ts/nosqldb/classes.atomicdelete.d.ts +26 -0
- package/dist_ts/nosqldb/classes.atomicdelete.js +44 -0
- package/dist_ts/nosqldb/classes.atomicfindoneandupdate.d.ts +27 -0
- package/dist_ts/nosqldb/classes.atomicfindoneandupdate.js +86 -0
- package/dist_ts/nosqldb/classes.atomicupdate.d.ts +26 -0
- package/dist_ts/nosqldb/classes.atomicupdate.js +55 -0
- package/dist_ts/nosqldb/classes.bootstraprecord.d.ts +14 -0
- package/dist_ts/nosqldb/classes.bootstraprecord.js +80 -0
- package/dist_ts/nosqldb/classes.bsonassertion.d.ts +2 -0
- package/dist_ts/nosqldb/classes.bsonassertion.js +29 -0
- package/dist_ts/nosqldb/classes.bsonobjectid.d.ts +2 -0
- package/dist_ts/nosqldb/classes.bsonobjectid.js +50 -0
- package/dist_ts/nosqldb/classes.bsonsnapshot.d.ts +3 -0
- package/dist_ts/nosqldb/classes.bsonsnapshot.js +126 -0
- package/dist_ts/nosqldb/classes.cached-document.d.ts +27 -0
- package/dist_ts/nosqldb/classes.cached-document.js +112 -0
- package/dist_ts/nosqldb/classes.collection.d.ts +302 -0
- package/dist_ts/nosqldb/classes.collection.js +1568 -0
- package/dist_ts/nosqldb/classes.collectionfactory.d.ts +30 -0
- package/dist_ts/nosqldb/classes.collectionfactory.js +65 -0
- package/dist_ts/nosqldb/classes.collectionlifecycle.d.ts +4 -0
- package/dist_ts/nosqldb/classes.collectionlifecycle.js +15 -0
- package/dist_ts/nosqldb/classes.collectionpreparation.d.ts +34 -0
- package/dist_ts/nosqldb/classes.collectionpreparation.js +134 -0
- package/dist_ts/nosqldb/classes.collectiontopology.d.ts +47 -0
- package/dist_ts/nosqldb/classes.collectiontopology.js +388 -0
- package/dist_ts/nosqldb/classes.connection.d.ts +18 -0
- package/dist_ts/nosqldb/classes.connection.js +23 -0
- package/dist_ts/nosqldb/classes.convenience.d.ts +1 -0
- package/dist_ts/nosqldb/classes.convenience.js +5 -0
- package/dist_ts/nosqldb/classes.cursor.d.ts +15 -0
- package/dist_ts/nosqldb/classes.cursor.js +82 -0
- package/dist_ts/nosqldb/classes.cursoroperation.d.ts +7 -0
- package/dist_ts/nosqldb/classes.cursoroperation.js +36 -0
- package/dist_ts/nosqldb/classes.db.d.ts +98 -0
- package/dist_ts/nosqldb/classes.db.js +434 -0
- package/dist_ts/nosqldb/classes.distributedcoordinator.d.ts +52 -0
- package/dist_ts/nosqldb/classes.distributedcoordinator.js +314 -0
- package/dist_ts/nosqldb/classes.doc.d.ts +722 -0
- package/dist_ts/nosqldb/classes.doc.js +2976 -0
- package/dist_ts/nosqldb/classes.easystore.d.ts +42 -0
- package/dist_ts/nosqldb/classes.easystore.js +199 -0
- package/dist_ts/nosqldb/classes.exactpersistence.d.ts +141 -0
- package/dist_ts/nosqldb/classes.exactpersistence.js +1110 -0
- package/dist_ts/nosqldb/classes.lucene.adapter.d.ts +173 -0
- package/dist_ts/nosqldb/classes.lucene.adapter.js +623 -0
- package/dist_ts/nosqldb/classes.mongoadministration.d.ts +73 -0
- package/dist_ts/nosqldb/classes.mongoadministration.js +497 -0
- package/dist_ts/nosqldb/classes.namespaceinspection.d.ts +42 -0
- package/dist_ts/nosqldb/classes.namespaceinspection.js +138 -0
- package/dist_ts/nosqldb/classes.operationbudget.d.ts +22 -0
- package/dist_ts/nosqldb/classes.operationbudget.js +65 -0
- package/dist_ts/nosqldb/classes.ordinarypersistence.d.ts +18 -0
- package/dist_ts/nosqldb/classes.ordinarypersistence.js +71 -0
- package/dist_ts/nosqldb/classes.persistence.d.ts +14 -0
- package/dist_ts/nosqldb/classes.persistence.js +34 -0
- package/dist_ts/nosqldb/classes.session.d.ts +28 -0
- package/dist_ts/nosqldb/classes.session.js +246 -0
- package/dist_ts/nosqldb/classes.storedinspection.d.ts +44 -0
- package/dist_ts/nosqldb/classes.storedinspection.js +100 -0
- package/dist_ts/nosqldb/classes.testdatabase.d.ts +56 -0
- package/dist_ts/nosqldb/classes.testdatabase.js +250 -0
- package/dist_ts/nosqldb/classes.watcher.d.ts +37 -0
- package/dist_ts/nosqldb/classes.watcher.js +98 -0
- package/dist_ts/nosqldb/index.d.ts +27 -0
- package/dist_ts/nosqldb/index.js +18 -0
- package/dist_ts/nosqldb/logging.d.ts +2 -0
- package/dist_ts/nosqldb/logging.js +3 -0
- package/dist_ts/nosqldb/plugins.d.ts +17 -0
- package/dist_ts/nosqldb/plugins.js +20 -0
- package/dist_ts/nosqldb/shim.d.ts +1 -0
- package/dist_ts/nosqldb/shim.js +8 -0
- package/dist_ts/nosqldb/testsupport.d.ts +3 -0
- package/dist_ts/nosqldb/testsupport.js +3 -0
- package/dist_ts/objectstorage/classes.bucket.d.ts +227 -0
- package/dist_ts/objectstorage/classes.bucket.js +939 -0
- package/dist_ts/objectstorage/classes.connection.d.ts +21 -0
- package/dist_ts/objectstorage/classes.connection.js +27 -0
- package/dist_ts/objectstorage/classes.directory.d.ts +124 -0
- package/dist_ts/objectstorage/classes.directory.js +335 -0
- package/dist_ts/objectstorage/classes.exactpathpurgeerror.d.ts +5 -0
- package/dist_ts/objectstorage/classes.exactpathpurgeerror.js +18 -0
- package/dist_ts/objectstorage/classes.exactuploaderror.d.ts +5 -0
- package/dist_ts/objectstorage/classes.exactuploaderror.js +19 -0
- package/dist_ts/objectstorage/classes.file.d.ts +91 -0
- package/dist_ts/objectstorage/classes.file.js +255 -0
- package/dist_ts/objectstorage/classes.listcursor.d.ts +41 -0
- package/dist_ts/objectstorage/classes.listcursor.js +67 -0
- package/dist_ts/objectstorage/classes.metadata.d.ts +57 -0
- package/dist_ts/objectstorage/classes.metadata.js +113 -0
- package/dist_ts/objectstorage/classes.smartbucket.d.ts +57 -0
- package/dist_ts/objectstorage/classes.smartbucket.js +357 -0
- package/dist_ts/objectstorage/classes.trash.d.ts +11 -0
- package/dist_ts/objectstorage/classes.trash.js +22 -0
- package/dist_ts/objectstorage/classes.watcher.d.ts +79 -0
- package/dist_ts/objectstorage/classes.watcher.js +249 -0
- package/dist_ts/objectstorage/helpers.d.ts +25 -0
- package/dist_ts/objectstorage/helpers.js +215 -0
- package/dist_ts/objectstorage/index.d.ts +13 -0
- package/dist_ts/objectstorage/index.js +13 -0
- package/dist_ts/objectstorage/interfaces.d.ts +276 -0
- package/dist_ts/objectstorage/interfaces.js +2 -0
- package/dist_ts/objectstorage/internal.exactpathpurge.operations.d.ts +11 -0
- package/dist_ts/objectstorage/internal.exactpathpurge.operations.js +1069 -0
- package/dist_ts/objectstorage/internal.exactupload.capability.d.ts +40 -0
- package/dist_ts/objectstorage/internal.exactupload.capability.js +382 -0
- package/dist_ts/objectstorage/internal.exactupload.operations.d.ts +11 -0
- package/dist_ts/objectstorage/internal.exactupload.operations.js +1104 -0
- package/dist_ts/objectstorage/internal.multipart.planner.d.ts +8 -0
- package/dist_ts/objectstorage/internal.multipart.planner.js +63 -0
- package/dist_ts/objectstorage/internal.multipart.stream.d.ts +17 -0
- package/dist_ts/objectstorage/internal.multipart.stream.js +440 -0
- package/dist_ts/objectstorage/internal.multipart.types.d.ts +82 -0
- package/dist_ts/objectstorage/internal.multipart.types.js +2 -0
- package/dist_ts/objectstorage/plugins.d.ts +17 -0
- package/dist_ts/objectstorage/plugins.js +23 -0
- package/dist_ts/plugins.d.ts +4 -0
- package/dist_ts/plugins.js +5 -0
- package/dist_ts/sqldb/classes.clickhouseconnection.d.ts +39 -0
- package/dist_ts/sqldb/classes.clickhouseconnection.js +225 -0
- package/dist_ts/sqldb/classes.sqlconnection.d.ts +50 -0
- package/dist_ts/sqldb/classes.sqlconnection.js +376 -0
- package/dist_ts/sqldb/classes.sqltable.d.ts +29 -0
- package/dist_ts/sqldb/classes.sqltable.js +70 -0
- package/dist_ts/sqldb/clickhouse/classes.metricwriter.d.ts +27 -0
- package/dist_ts/sqldb/clickhouse/classes.metricwriter.js +89 -0
- package/dist_ts/sqldb/clickhouse/index.d.ts +9 -0
- package/dist_ts/sqldb/clickhouse/index.js +13 -0
- package/dist_ts/sqldb/clickhouse/smartclickhouse.classes.clickhousetable.d.ts +88 -0
- package/dist_ts/sqldb/clickhouse/smartclickhouse.classes.clickhousetable.js +304 -0
- package/dist_ts/sqldb/clickhouse/smartclickhouse.classes.httpclient.d.ts +28 -0
- package/dist_ts/sqldb/clickhouse/smartclickhouse.classes.httpclient.js +46 -0
- package/dist_ts/sqldb/clickhouse/smartclickhouse.classes.querybuilder.d.ts +43 -0
- package/dist_ts/sqldb/clickhouse/smartclickhouse.classes.querybuilder.js +155 -0
- package/dist_ts/sqldb/clickhouse/smartclickhouse.classes.resultset.d.ts +13 -0
- package/dist_ts/sqldb/clickhouse/smartclickhouse.classes.resultset.js +36 -0
- package/dist_ts/sqldb/clickhouse/smartclickhouse.classes.smartclickhouse.d.ts +49 -0
- package/dist_ts/sqldb/clickhouse/smartclickhouse.classes.smartclickhouse.js +106 -0
- package/dist_ts/sqldb/clickhouse/smartclickhouse.classes.timedatatable.d.ts +51 -0
- package/dist_ts/sqldb/clickhouse/smartclickhouse.classes.timedatatable.js +96 -0
- package/dist_ts/sqldb/clickhouse/smartclickhouse.plugins.d.ts +5 -0
- package/dist_ts/sqldb/clickhouse/smartclickhouse.plugins.js +6 -0
- package/dist_ts/sqldb/clickhouse/smartclickhouse.types.d.ts +53 -0
- package/dist_ts/sqldb/clickhouse/smartclickhouse.types.js +41 -0
- package/dist_ts/sqldb/index.d.ts +6 -0
- package/dist_ts/sqldb/index.js +6 -0
- package/dist_ts/sqldb/interfaces.d.ts +53 -0
- package/dist_ts/sqldb/interfaces.js +19 -0
- package/dist_ts/sqldb/internal.sqlpool.d.ts +51 -0
- package/dist_ts/sqldb/internal.sqlpool.js +214 -0
- package/dist_ts/sqldb/plugins.clickhouse.d.ts +4 -0
- package/dist_ts/sqldb/plugins.clickhouse.js +5 -0
- package/dist_ts/sqldb/plugins.mariadb.d.ts +4 -0
- package/dist_ts/sqldb/plugins.mariadb.js +5 -0
- package/docs/source/smartbucket/license.md +19 -0
- package/docs/source/smartclickhouse/license.md +19 -0
- package/license.md +21 -0
- package/package.json +101 -0
- package/readme.md +157 -0
- package/ts/00_commitinfo_data.ts +8 -0
- package/ts/classes.losslessorgclient.ts +104 -0
- package/ts/core/classes.error.ts +31 -0
- package/ts/core/classes.operation.ts +60 -0
- package/ts/core/interfaces.ts +24 -0
- package/ts/index.ts +4 -0
- package/ts/nosqldb/classes.atomicdelete.ts +81 -0
- package/ts/nosqldb/classes.atomicfindoneandupdate.ts +152 -0
- package/ts/nosqldb/classes.atomicupdate.ts +99 -0
- package/ts/nosqldb/classes.bootstraprecord.ts +107 -0
- package/ts/nosqldb/classes.bsonassertion.ts +25 -0
- package/ts/nosqldb/classes.bsonobjectid.ts +45 -0
- package/ts/nosqldb/classes.bsonsnapshot.ts +105 -0
- package/ts/nosqldb/classes.cached-document.ts +67 -0
- package/ts/nosqldb/classes.collection.ts +2399 -0
- package/ts/nosqldb/classes.collectionfactory.ts +87 -0
- package/ts/nosqldb/classes.collectionlifecycle.ts +24 -0
- package/ts/nosqldb/classes.collectionpreparation.ts +164 -0
- package/ts/nosqldb/classes.collectiontopology.ts +645 -0
- package/ts/nosqldb/classes.connection.ts +31 -0
- package/ts/nosqldb/classes.convenience.ts +5 -0
- package/ts/nosqldb/classes.cursor.ts +88 -0
- package/ts/nosqldb/classes.cursoroperation.ts +38 -0
- package/ts/nosqldb/classes.db.ts +637 -0
- package/ts/nosqldb/classes.distributedcoordinator.ts +305 -0
- package/ts/nosqldb/classes.doc.ts +4928 -0
- package/ts/nosqldb/classes.easystore.ts +154 -0
- package/ts/nosqldb/classes.exactpersistence.ts +1974 -0
- package/ts/nosqldb/classes.lucene.adapter.ts +780 -0
- package/ts/nosqldb/classes.mongoadministration.ts +867 -0
- package/ts/nosqldb/classes.namespaceinspection.ts +199 -0
- package/ts/nosqldb/classes.operationbudget.ts +75 -0
- package/ts/nosqldb/classes.ordinarypersistence.ts +84 -0
- package/ts/nosqldb/classes.persistence.ts +62 -0
- package/ts/nosqldb/classes.session.ts +389 -0
- package/ts/nosqldb/classes.storedinspection.ts +151 -0
- package/ts/nosqldb/classes.testdatabase.ts +272 -0
- package/ts/nosqldb/classes.watcher.ts +96 -0
- package/ts/nosqldb/index.ts +51 -0
- package/ts/nosqldb/logging.ts +3 -0
- package/ts/nosqldb/plugins.ts +37 -0
- package/ts/nosqldb/shim.ts +6 -0
- package/ts/nosqldb/testsupport.ts +13 -0
- package/ts/objectstorage/classes.bucket.ts +1114 -0
- package/ts/objectstorage/classes.connection.ts +36 -0
- package/ts/objectstorage/classes.directory.ts +425 -0
- package/ts/objectstorage/classes.exactpathpurgeerror.ts +24 -0
- package/ts/objectstorage/classes.exactuploaderror.ts +25 -0
- package/ts/objectstorage/classes.file.ts +303 -0
- package/ts/objectstorage/classes.listcursor.ts +89 -0
- package/ts/objectstorage/classes.metadata.ts +134 -0
- package/ts/objectstorage/classes.smartbucket.ts +445 -0
- package/ts/objectstorage/classes.trash.ts +30 -0
- package/ts/objectstorage/classes.watcher.ts +289 -0
- package/ts/objectstorage/helpers.ts +254 -0
- package/ts/objectstorage/index.ts +13 -0
- package/ts/objectstorage/interfaces.ts +389 -0
- package/ts/objectstorage/internal.exactpathpurge.operations.ts +1936 -0
- package/ts/objectstorage/internal.exactupload.capability.ts +580 -0
- package/ts/objectstorage/internal.exactupload.operations.ts +1715 -0
- package/ts/objectstorage/internal.multipart.planner.ts +90 -0
- package/ts/objectstorage/internal.multipart.stream.ts +606 -0
- package/ts/objectstorage/internal.multipart.types.ts +106 -0
- package/ts/objectstorage/plugins.ts +35 -0
- package/ts/plugins.ts +4 -0
- package/ts/sqldb/classes.clickhouseconnection.ts +189 -0
- package/ts/sqldb/classes.sqlconnection.ts +350 -0
- package/ts/sqldb/classes.sqltable.ts +70 -0
- package/ts/sqldb/clickhouse/classes.metricwriter.ts +72 -0
- package/ts/sqldb/clickhouse/index.ts +16 -0
- package/ts/sqldb/clickhouse/smartclickhouse.classes.clickhousetable.ts +372 -0
- package/ts/sqldb/clickhouse/smartclickhouse.classes.httpclient.ts +52 -0
- package/ts/sqldb/clickhouse/smartclickhouse.classes.querybuilder.ts +120 -0
- package/ts/sqldb/clickhouse/smartclickhouse.classes.resultset.ts +44 -0
- package/ts/sqldb/clickhouse/smartclickhouse.classes.smartclickhouse.ts +123 -0
- package/ts/sqldb/clickhouse/smartclickhouse.classes.timedatatable.ts +114 -0
- package/ts/sqldb/clickhouse/smartclickhouse.plugins.ts +5 -0
- package/ts/sqldb/clickhouse/smartclickhouse.types.ts +134 -0
- package/ts/sqldb/index.ts +6 -0
- package/ts/sqldb/interfaces.ts +61 -0
- package/ts/sqldb/internal.sqlpool.ts +179 -0
- package/ts/sqldb/plugins.clickhouse.ts +4 -0
- package/ts/sqldb/plugins.mariadb.ts +4 -0
|
@@ -0,0 +1,939 @@
|
|
|
1
|
+
// classes.bucket.ts
|
|
2
|
+
import * as plugins from './plugins.js';
|
|
3
|
+
import * as helpers from './helpers.js';
|
|
4
|
+
import * as interfaces from './interfaces.js';
|
|
5
|
+
import { SmartBucket } from './classes.smartbucket.js';
|
|
6
|
+
import { Directory } from './classes.directory.js';
|
|
7
|
+
import { File } from './classes.file.js';
|
|
8
|
+
import { Trash } from './classes.trash.js';
|
|
9
|
+
import { ListCursor } from './classes.listcursor.js';
|
|
10
|
+
import { BucketWatcher } from './classes.watcher.js';
|
|
11
|
+
import { fastPutStreamExact as fastPutStreamExactOperation, probeExactUploadCapability as probeExactUploadCapabilityOperation, } from './internal.exactupload.operations.js';
|
|
12
|
+
import { probeExactPathPurgeCapability as probeExactPathPurgeCapabilityOperation, purgeExactPath as purgeExactPathOperation, } from './internal.exactpathpurge.operations.js';
|
|
13
|
+
import { beginBasicBucketOperation } from './internal.exactupload.capability.js';
|
|
14
|
+
const compareUtf8ObjectKeys = (leftArg, rightArg) => Buffer.compare(Buffer.from(leftArg, 'utf8'), Buffer.from(rightArg, 'utf8'));
|
|
15
|
+
const destroyReadableAndWaitForSettlement = async (readableArg) => {
|
|
16
|
+
let removeFinishedListeners = () => { };
|
|
17
|
+
const settlement = new Promise((resolveArg) => {
|
|
18
|
+
removeFinishedListeners = plugins.stream.finished(readableArg, { readable: true, writable: false }, () => resolveArg(true));
|
|
19
|
+
});
|
|
20
|
+
readableArg.destroy();
|
|
21
|
+
let settlementDeadline;
|
|
22
|
+
let settled = false;
|
|
23
|
+
try {
|
|
24
|
+
settled = await Promise.race([
|
|
25
|
+
settlement,
|
|
26
|
+
new Promise((resolveArg) => {
|
|
27
|
+
settlementDeadline = setTimeout(() => resolveArg(false), 5_000);
|
|
28
|
+
}),
|
|
29
|
+
]);
|
|
30
|
+
}
|
|
31
|
+
finally {
|
|
32
|
+
if (settlementDeadline) {
|
|
33
|
+
clearTimeout(settlementDeadline);
|
|
34
|
+
}
|
|
35
|
+
removeFinishedListeners();
|
|
36
|
+
}
|
|
37
|
+
if (!settled && !readableArg.closed) {
|
|
38
|
+
const onLateError = () => {
|
|
39
|
+
readableArg.removeListener('close', onLateClose);
|
|
40
|
+
};
|
|
41
|
+
const onLateClose = () => {
|
|
42
|
+
readableArg.removeListener('error', onLateError);
|
|
43
|
+
};
|
|
44
|
+
readableArg.once('error', onLateError);
|
|
45
|
+
readableArg.once('close', onLateClose);
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
/**
|
|
49
|
+
* The bucket class exposes the basic functionality of a bucket.
|
|
50
|
+
* The functions of the bucket alone are enough to
|
|
51
|
+
* operate on blobs of data in an S3-compatible object store.
|
|
52
|
+
*/
|
|
53
|
+
export class Bucket {
|
|
54
|
+
static async getBucketByName(smartbucketRef, bucketNameArg) {
|
|
55
|
+
const command = new plugins.s3.ListBucketsCommand({});
|
|
56
|
+
const buckets = await smartbucketRef.storageClient.send(command);
|
|
57
|
+
const foundBucket = buckets.Buckets.find((bucket) => bucket.Name === bucketNameArg);
|
|
58
|
+
if (foundBucket) {
|
|
59
|
+
console.log(`bucket with name ${bucketNameArg} exists.`);
|
|
60
|
+
console.log(`Taking this as base for new Bucket instance`);
|
|
61
|
+
return new this(smartbucketRef, bucketNameArg);
|
|
62
|
+
}
|
|
63
|
+
else {
|
|
64
|
+
throw new Error(`Bucket '${bucketNameArg}' not found.`);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
static async createBucketByName(smartbucketRef, bucketName) {
|
|
68
|
+
const command = new plugins.s3.CreateBucketCommand({ Bucket: bucketName });
|
|
69
|
+
await smartbucketRef.storageClient.send(command);
|
|
70
|
+
return new Bucket(smartbucketRef, bucketName);
|
|
71
|
+
}
|
|
72
|
+
static async removeBucketByName(smartbucketRef, bucketName) {
|
|
73
|
+
const command = new plugins.s3.DeleteBucketCommand({ Bucket: bucketName });
|
|
74
|
+
await smartbucketRef.storageClient.send(command);
|
|
75
|
+
}
|
|
76
|
+
smartbucketRef;
|
|
77
|
+
name;
|
|
78
|
+
constructor(smartbucketRef, bucketName) {
|
|
79
|
+
this.smartbucketRef = smartbucketRef;
|
|
80
|
+
this.name = bucketName;
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Returns the underlying AWS SDK v3 S3Client for this bucket.
|
|
84
|
+
*
|
|
85
|
+
* Use this when you need to perform operations smartbucket doesn't
|
|
86
|
+
* wrap directly (e.g. lifecycle policies, bucket tagging, multipart
|
|
87
|
+
* upload control, object-lock, inventory config, etc.).
|
|
88
|
+
*
|
|
89
|
+
* The returned client is shared with the parent SmartBucket — do not
|
|
90
|
+
* call `.destroy()` on it.
|
|
91
|
+
*/
|
|
92
|
+
getStorageClient() {
|
|
93
|
+
return this.smartbucketRef.storageClient;
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Performs a live, side-effectful provider probe for the conditional S3
|
|
97
|
+
* semantics required by fastPutStreamExact().
|
|
98
|
+
*
|
|
99
|
+
* Probe objects and multipart uploads use unique private keys and are removed
|
|
100
|
+
* before a capability is returned. A capability becomes stale when the
|
|
101
|
+
* Bucket object, bucket name, parent SmartBucket, S3 client, or SmartBucket
|
|
102
|
+
* lifecycle generation changes.
|
|
103
|
+
*/
|
|
104
|
+
probeExactUploadCapability(optionsArg = {}) {
|
|
105
|
+
return probeExactUploadCapabilityOperation(this, optionsArg);
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Performs a live provider probe for exact conditional deletion,
|
|
109
|
+
* version-specific deletion, delete-marker removal, and verified cleanup.
|
|
110
|
+
*/
|
|
111
|
+
probeExactPathPurgeCapability(optionsArg = {}) {
|
|
112
|
+
return probeExactPathPurgeCapabilityOperation(this, optionsArg);
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* gets the base directory of the bucket
|
|
116
|
+
*/
|
|
117
|
+
async getBaseDirectory() {
|
|
118
|
+
return new Directory(this, null, '');
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* gets the trash directory
|
|
122
|
+
*/
|
|
123
|
+
async getTrash() {
|
|
124
|
+
const trash = new Trash(this);
|
|
125
|
+
return trash;
|
|
126
|
+
}
|
|
127
|
+
async getDirectoryFromPath(pathDescriptorArg) {
|
|
128
|
+
if (!pathDescriptorArg.path && !pathDescriptorArg.directory) {
|
|
129
|
+
return this.getBaseDirectory();
|
|
130
|
+
}
|
|
131
|
+
const checkPath = await helpers.reducePathDescriptorToPath(pathDescriptorArg);
|
|
132
|
+
const baseDirectory = await this.getBaseDirectory();
|
|
133
|
+
return await baseDirectory.getSubDirectoryByName(checkPath, {
|
|
134
|
+
getEmptyDirectory: true,
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
// ===============
|
|
138
|
+
// Fast Operations
|
|
139
|
+
// ===============
|
|
140
|
+
/**
|
|
141
|
+
* store file
|
|
142
|
+
*/
|
|
143
|
+
async fastPut(optionsArg) {
|
|
144
|
+
try {
|
|
145
|
+
const reducedPath = await helpers.reducePathDescriptorToPath(optionsArg);
|
|
146
|
+
const exists = await this.fastExists({ path: reducedPath });
|
|
147
|
+
if (exists && !optionsArg.overwrite) {
|
|
148
|
+
throw new Error(`Object already exists at path '${reducedPath}' in bucket '${this.name}'. ` +
|
|
149
|
+
`Set overwrite:true to replace it.`);
|
|
150
|
+
}
|
|
151
|
+
else if (exists && optionsArg.overwrite) {
|
|
152
|
+
console.log(`Overwriting existing object at path '${reducedPath}' in bucket '${this.name}'.`);
|
|
153
|
+
}
|
|
154
|
+
else {
|
|
155
|
+
console.log(`Creating new object at path '${reducedPath}' in bucket '${this.name}'.`);
|
|
156
|
+
}
|
|
157
|
+
const command = new plugins.s3.PutObjectCommand({
|
|
158
|
+
Bucket: this.name,
|
|
159
|
+
Key: reducedPath,
|
|
160
|
+
Body: optionsArg.contents,
|
|
161
|
+
});
|
|
162
|
+
await this.smartbucketRef.storageClient.send(command);
|
|
163
|
+
console.log(`Object '${reducedPath}' has been successfully stored in bucket '${this.name}'.`);
|
|
164
|
+
const parsedPath = plugins.path.parse(reducedPath);
|
|
165
|
+
return new File({
|
|
166
|
+
directoryRefArg: await this.getDirectoryFromPath({
|
|
167
|
+
path: parsedPath.dir,
|
|
168
|
+
}),
|
|
169
|
+
fileName: parsedPath.base,
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
catch (error) {
|
|
173
|
+
console.error(`Error storing object at path '${optionsArg.path}' in bucket '${this.name}':`, error);
|
|
174
|
+
throw error;
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* get file
|
|
179
|
+
*/
|
|
180
|
+
async fastGet(optionsArg) {
|
|
181
|
+
const source = await this.fastGetStream(optionsArg);
|
|
182
|
+
const chunks = [];
|
|
183
|
+
try {
|
|
184
|
+
for await (const chunk of source)
|
|
185
|
+
chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
|
|
186
|
+
return Buffer.concat(chunks);
|
|
187
|
+
}
|
|
188
|
+
finally {
|
|
189
|
+
source.destroy();
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
/**
|
|
193
|
+
* good when time to first byte is important
|
|
194
|
+
* and multiple subscribers are expected
|
|
195
|
+
* @param optionsArg
|
|
196
|
+
* @returns
|
|
197
|
+
*/
|
|
198
|
+
async fastGetReplaySubject(optionsArg) {
|
|
199
|
+
const command = new plugins.s3.GetObjectCommand({
|
|
200
|
+
Bucket: this.name,
|
|
201
|
+
Key: optionsArg.path,
|
|
202
|
+
});
|
|
203
|
+
const response = await this.smartbucketRef.storageClient.send(command);
|
|
204
|
+
const replaySubject = new plugins.smartrx.rxjs.ReplaySubject();
|
|
205
|
+
// Convert the stream to a format that supports piping
|
|
206
|
+
const stream = response.Body; // SdkStreamMixin includes readable stream
|
|
207
|
+
if (typeof stream.pipe === 'function') {
|
|
208
|
+
const duplexStream = new plugins.smartstream.SmartDuplex({
|
|
209
|
+
writeFunction: async (chunk) => {
|
|
210
|
+
replaySubject.next(chunk);
|
|
211
|
+
return;
|
|
212
|
+
},
|
|
213
|
+
finalFunction: async (cb) => {
|
|
214
|
+
replaySubject.complete();
|
|
215
|
+
return;
|
|
216
|
+
},
|
|
217
|
+
});
|
|
218
|
+
stream.pipe(duplexStream);
|
|
219
|
+
}
|
|
220
|
+
return replaySubject;
|
|
221
|
+
}
|
|
222
|
+
async fastGetStream(optionsArg, typeArg = 'nodestream') {
|
|
223
|
+
const operation = beginBasicBucketOperation(this, optionsArg.signal);
|
|
224
|
+
const disposeBody = async (responseBodyArg) => {
|
|
225
|
+
try {
|
|
226
|
+
if (responseBodyArg instanceof plugins.stream.Readable) {
|
|
227
|
+
await destroyReadableAndWaitForSettlement(responseBodyArg);
|
|
228
|
+
}
|
|
229
|
+
else if (typeof ReadableStream !== 'undefined'
|
|
230
|
+
&& responseBodyArg instanceof ReadableStream) {
|
|
231
|
+
await responseBodyArg.cancel();
|
|
232
|
+
}
|
|
233
|
+
else if (typeof responseBodyArg === 'object'
|
|
234
|
+
&& responseBodyArg !== null
|
|
235
|
+
&& typeof responseBodyArg.destroy === 'function') {
|
|
236
|
+
responseBodyArg.destroy();
|
|
237
|
+
}
|
|
238
|
+
else if (typeof responseBodyArg === 'object'
|
|
239
|
+
&& responseBodyArg !== null
|
|
240
|
+
&& typeof responseBodyArg.cancel === 'function') {
|
|
241
|
+
await responseBodyArg.cancel();
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
catch {
|
|
245
|
+
// Preserve the primary response-body or conversion failure.
|
|
246
|
+
}
|
|
247
|
+
};
|
|
248
|
+
let response;
|
|
249
|
+
try {
|
|
250
|
+
response = await operation.runProvider(() => operation.client.send(new plugins.s3.GetObjectCommand({
|
|
251
|
+
Bucket: operation.bucketName,
|
|
252
|
+
Key: optionsArg.path,
|
|
253
|
+
}), { abortSignal: operation.signal }), {
|
|
254
|
+
disposeLateResult: async (lateResponseArg) => {
|
|
255
|
+
await disposeBody(lateResponseArg.Body);
|
|
256
|
+
},
|
|
257
|
+
});
|
|
258
|
+
}
|
|
259
|
+
catch (error) {
|
|
260
|
+
operation.finish();
|
|
261
|
+
throw error;
|
|
262
|
+
}
|
|
263
|
+
const responseBody = response.Body;
|
|
264
|
+
const disposeResponseBody = async () => {
|
|
265
|
+
await disposeBody(responseBody);
|
|
266
|
+
};
|
|
267
|
+
let sourceStream = null;
|
|
268
|
+
try {
|
|
269
|
+
sourceStream = responseBody instanceof plugins.stream.Readable
|
|
270
|
+
? responseBody
|
|
271
|
+
: (typeof ReadableStream !== 'undefined'
|
|
272
|
+
&& responseBody instanceof ReadableStream)
|
|
273
|
+
? plugins.stream.Readable.fromWeb(responseBody)
|
|
274
|
+
: null;
|
|
275
|
+
}
|
|
276
|
+
catch (error) {
|
|
277
|
+
await disposeResponseBody();
|
|
278
|
+
operation.finish();
|
|
279
|
+
throw error;
|
|
280
|
+
}
|
|
281
|
+
if (!sourceStream) {
|
|
282
|
+
await disposeResponseBody();
|
|
283
|
+
operation.finish();
|
|
284
|
+
throw new Error('S3 GetObject returned no supported response stream.');
|
|
285
|
+
}
|
|
286
|
+
const outputStream = new plugins.stream.PassThrough();
|
|
287
|
+
const abortError = () => {
|
|
288
|
+
if (operation.signal.reason instanceof Error) {
|
|
289
|
+
return operation.signal.reason;
|
|
290
|
+
}
|
|
291
|
+
const error = new Error('S3 object download was aborted.');
|
|
292
|
+
error.name = 'AbortError';
|
|
293
|
+
return error;
|
|
294
|
+
};
|
|
295
|
+
let sourceEnded = false;
|
|
296
|
+
let forwardingCleanedUp = false;
|
|
297
|
+
let sourceErrorGuardReleased = false;
|
|
298
|
+
const preventUnhandledSourceError = () => { };
|
|
299
|
+
const preventUnhandledOutputError = () => { };
|
|
300
|
+
const cleanupForwarding = () => {
|
|
301
|
+
if (forwardingCleanedUp) {
|
|
302
|
+
return;
|
|
303
|
+
}
|
|
304
|
+
forwardingCleanedUp = true;
|
|
305
|
+
operation.signal.removeEventListener('abort', onAbort);
|
|
306
|
+
sourceStream.removeListener('error', onSourceError);
|
|
307
|
+
sourceStream.removeListener('end', onSourceEnd);
|
|
308
|
+
sourceStream.removeListener('close', onSourceClose);
|
|
309
|
+
outputStream.removeListener('error', preventUnhandledOutputError);
|
|
310
|
+
outputStream.removeListener('close', onOutputClose);
|
|
311
|
+
};
|
|
312
|
+
const releaseSourceErrorGuard = () => {
|
|
313
|
+
if (sourceErrorGuardReleased) {
|
|
314
|
+
return;
|
|
315
|
+
}
|
|
316
|
+
sourceErrorGuardReleased = true;
|
|
317
|
+
sourceStream.removeListener('error', preventUnhandledSourceError);
|
|
318
|
+
};
|
|
319
|
+
let sourceSettlement;
|
|
320
|
+
const settleSource = () => {
|
|
321
|
+
sourceSettlement ??= destroyReadableAndWaitForSettlement(sourceStream);
|
|
322
|
+
return sourceSettlement;
|
|
323
|
+
};
|
|
324
|
+
const finishAfterSourceSettlement = async () => {
|
|
325
|
+
await settleSource();
|
|
326
|
+
releaseSourceErrorGuard();
|
|
327
|
+
operation.finish();
|
|
328
|
+
};
|
|
329
|
+
const onAbort = () => {
|
|
330
|
+
const error = abortError();
|
|
331
|
+
outputStream.destroy(error);
|
|
332
|
+
void settleSource();
|
|
333
|
+
};
|
|
334
|
+
const onSourceError = (errorArg) => {
|
|
335
|
+
outputStream.destroy(errorArg);
|
|
336
|
+
};
|
|
337
|
+
const onSourceEnd = () => {
|
|
338
|
+
sourceEnded = true;
|
|
339
|
+
};
|
|
340
|
+
const onSourceClose = () => {
|
|
341
|
+
if (!sourceEnded && !outputStream.destroyed) {
|
|
342
|
+
outputStream.destroy(new Error('S3 object download stream closed before completion.'));
|
|
343
|
+
}
|
|
344
|
+
};
|
|
345
|
+
const onOutputClose = () => {
|
|
346
|
+
cleanupForwarding();
|
|
347
|
+
if (sourceStream.closed) {
|
|
348
|
+
releaseSourceErrorGuard();
|
|
349
|
+
operation.finish();
|
|
350
|
+
}
|
|
351
|
+
else {
|
|
352
|
+
void finishAfterSourceSettlement();
|
|
353
|
+
}
|
|
354
|
+
};
|
|
355
|
+
sourceStream.on('error', preventUnhandledSourceError);
|
|
356
|
+
sourceStream.once('error', onSourceError);
|
|
357
|
+
sourceStream.once('end', onSourceEnd);
|
|
358
|
+
sourceStream.once('close', onSourceClose);
|
|
359
|
+
outputStream.on('error', preventUnhandledOutputError);
|
|
360
|
+
outputStream.once('close', onOutputClose);
|
|
361
|
+
operation.signal.addEventListener('abort', onAbort, { once: true });
|
|
362
|
+
if (sourceStream.closed) {
|
|
363
|
+
sourceEnded = sourceStream.readableEnded;
|
|
364
|
+
onSourceClose();
|
|
365
|
+
}
|
|
366
|
+
if (operation.signal.aborted) {
|
|
367
|
+
const error = abortError();
|
|
368
|
+
cleanupForwarding();
|
|
369
|
+
outputStream.destroy();
|
|
370
|
+
await settleSource();
|
|
371
|
+
releaseSourceErrorGuard();
|
|
372
|
+
operation.finish();
|
|
373
|
+
throw error;
|
|
374
|
+
}
|
|
375
|
+
let result;
|
|
376
|
+
try {
|
|
377
|
+
if (typeArg === 'nodestream') {
|
|
378
|
+
result = outputStream;
|
|
379
|
+
}
|
|
380
|
+
else if (typeArg === 'webstream') {
|
|
381
|
+
result = plugins.stream.Readable.toWeb(outputStream);
|
|
382
|
+
}
|
|
383
|
+
else {
|
|
384
|
+
throw new Error('unknown typeArg');
|
|
385
|
+
}
|
|
386
|
+
sourceStream.pipe(outputStream);
|
|
387
|
+
}
|
|
388
|
+
catch (error) {
|
|
389
|
+
cleanupForwarding();
|
|
390
|
+
outputStream.destroy();
|
|
391
|
+
await settleSource();
|
|
392
|
+
releaseSourceErrorGuard();
|
|
393
|
+
operation.finish();
|
|
394
|
+
throw error;
|
|
395
|
+
}
|
|
396
|
+
return result;
|
|
397
|
+
}
|
|
398
|
+
/**
|
|
399
|
+
* store file as stream
|
|
400
|
+
*/
|
|
401
|
+
async fastPutStream(optionsArg) {
|
|
402
|
+
if (optionsArg.contentLength !== undefined
|
|
403
|
+
&& (!Number.isSafeInteger(optionsArg.contentLength)
|
|
404
|
+
|| optionsArg.contentLength < 0)) {
|
|
405
|
+
throw new Error('contentLength must be a non-negative safe integer');
|
|
406
|
+
}
|
|
407
|
+
const operation = beginBasicBucketOperation(this, optionsArg.signal);
|
|
408
|
+
let uploadStream;
|
|
409
|
+
let sourceOwnershipStarted = false;
|
|
410
|
+
const disposeSource = async () => {
|
|
411
|
+
if (!uploadStream) {
|
|
412
|
+
if (optionsArg.readableStream instanceof plugins.stream.Readable) {
|
|
413
|
+
uploadStream = optionsArg.readableStream;
|
|
414
|
+
}
|
|
415
|
+
else {
|
|
416
|
+
const cancellation = optionsArg.readableStream.cancel().catch(() => undefined);
|
|
417
|
+
let cancellationDeadline;
|
|
418
|
+
try {
|
|
419
|
+
await Promise.race([
|
|
420
|
+
cancellation,
|
|
421
|
+
new Promise((resolveCancellationArg) => {
|
|
422
|
+
cancellationDeadline = setTimeout(resolveCancellationArg, 5_000);
|
|
423
|
+
}),
|
|
424
|
+
]);
|
|
425
|
+
}
|
|
426
|
+
finally {
|
|
427
|
+
if (cancellationDeadline) {
|
|
428
|
+
clearTimeout(cancellationDeadline);
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
return;
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
await destroyReadableAndWaitForSettlement(uploadStream);
|
|
435
|
+
};
|
|
436
|
+
let putDispatched = false;
|
|
437
|
+
try {
|
|
438
|
+
let exists;
|
|
439
|
+
try {
|
|
440
|
+
await operation.runProvider(() => operation.client.send(new plugins.s3.HeadObjectCommand({
|
|
441
|
+
Bucket: operation.bucketName,
|
|
442
|
+
Key: optionsArg.path,
|
|
443
|
+
}), { abortSignal: operation.signal }));
|
|
444
|
+
exists = true;
|
|
445
|
+
}
|
|
446
|
+
catch (error) {
|
|
447
|
+
try {
|
|
448
|
+
operation.assertCurrent();
|
|
449
|
+
}
|
|
450
|
+
catch (abortError) {
|
|
451
|
+
throw abortError;
|
|
452
|
+
}
|
|
453
|
+
if (error?.name === 'NotFound') {
|
|
454
|
+
exists = false;
|
|
455
|
+
}
|
|
456
|
+
else {
|
|
457
|
+
throw error;
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
if (exists && !optionsArg.overwrite) {
|
|
461
|
+
throw new Error(`Object already exists at path '${optionsArg.path}' in bucket '${this.name}'. ` +
|
|
462
|
+
`Set overwrite:true to replace it.`);
|
|
463
|
+
}
|
|
464
|
+
else if (exists && optionsArg.overwrite) {
|
|
465
|
+
console.log(`Overwriting existing object at path '${optionsArg.path}' in bucket '${this.name}'.`);
|
|
466
|
+
}
|
|
467
|
+
else {
|
|
468
|
+
console.log(`Creating new object at path '${optionsArg.path}' in bucket '${this.name}'.`);
|
|
469
|
+
}
|
|
470
|
+
sourceOwnershipStarted = true;
|
|
471
|
+
uploadStream = optionsArg.readableStream instanceof plugins.stream.Readable
|
|
472
|
+
? optionsArg.readableStream
|
|
473
|
+
: plugins.stream.Readable.fromWeb(optionsArg.readableStream);
|
|
474
|
+
const command = new plugins.s3.PutObjectCommand({
|
|
475
|
+
Bucket: operation.bucketName,
|
|
476
|
+
Key: optionsArg.path,
|
|
477
|
+
Body: uploadStream,
|
|
478
|
+
ContentLength: optionsArg.contentLength,
|
|
479
|
+
Metadata: optionsArg.nativeMetadata,
|
|
480
|
+
});
|
|
481
|
+
putDispatched = true;
|
|
482
|
+
await operation.runProvider(() => operation.client.send(command, { abortSignal: operation.signal }));
|
|
483
|
+
console.log(`Object '${optionsArg.path}' has been successfully stored in bucket '${this.name}'.`);
|
|
484
|
+
}
|
|
485
|
+
catch (error) {
|
|
486
|
+
if (sourceOwnershipStarted || putDispatched || operation.signal.aborted) {
|
|
487
|
+
await disposeSource();
|
|
488
|
+
}
|
|
489
|
+
console.error(`Error storing object at path '${optionsArg.path}' in bucket '${this.name}':`, error);
|
|
490
|
+
throw error;
|
|
491
|
+
}
|
|
492
|
+
finally {
|
|
493
|
+
operation.finish();
|
|
494
|
+
}
|
|
495
|
+
}
|
|
496
|
+
/**
|
|
497
|
+
* Creates an object from a stream while enforcing the declared byte length
|
|
498
|
+
* and create-only destination semantics.
|
|
499
|
+
*
|
|
500
|
+
* Non-empty inputs always use multipart upload and never fall back to a
|
|
501
|
+
* single streaming PutObject request. Memory is bounded by the returned
|
|
502
|
+
* multipart plan. Every source chunk must be no larger than the effective
|
|
503
|
+
* multipart part size (5 MiB by default, or requestedPartSize after protocol
|
|
504
|
+
* normalization).
|
|
505
|
+
*/
|
|
506
|
+
fastPutStreamExact(optionsArg) {
|
|
507
|
+
return fastPutStreamExactOperation(this, optionsArg);
|
|
508
|
+
}
|
|
509
|
+
/**
|
|
510
|
+
* Permanently removes the exact key, including every object version and
|
|
511
|
+
* delete marker, without deleting keys that merely share its prefix.
|
|
512
|
+
*/
|
|
513
|
+
purgeExactPath(optionsArg) {
|
|
514
|
+
return purgeExactPathOperation(this, optionsArg);
|
|
515
|
+
}
|
|
516
|
+
async fastCopy(optionsArg) {
|
|
517
|
+
const operation = beginBasicBucketOperation(this, optionsArg.signal);
|
|
518
|
+
try {
|
|
519
|
+
const targetBucketName = optionsArg.targetBucket ? optionsArg.targetBucket.name : this.name;
|
|
520
|
+
// Retrieve current object information to use in copy conditions
|
|
521
|
+
const currentObjInfo = await operation.runProvider(() => operation.client.send(new plugins.s3.HeadObjectCommand({
|
|
522
|
+
Bucket: operation.bucketName,
|
|
523
|
+
Key: optionsArg.sourcePath,
|
|
524
|
+
}), { abortSignal: operation.signal }));
|
|
525
|
+
// Prepare new metadata
|
|
526
|
+
const newNativeMetadata = {
|
|
527
|
+
...(optionsArg.deleteExistingNativeMetadata ? {} : currentObjInfo.Metadata),
|
|
528
|
+
...optionsArg.nativeMetadata,
|
|
529
|
+
};
|
|
530
|
+
// Define the copy operation
|
|
531
|
+
const copySource = `${operation.bucketName}/${optionsArg.sourcePath}`;
|
|
532
|
+
const command = new plugins.s3.CopyObjectCommand({
|
|
533
|
+
Bucket: targetBucketName,
|
|
534
|
+
CopySource: copySource,
|
|
535
|
+
Key: optionsArg.destinationPath || optionsArg.sourcePath,
|
|
536
|
+
Metadata: newNativeMetadata,
|
|
537
|
+
MetadataDirective: optionsArg.deleteExistingNativeMetadata ? 'REPLACE' : 'COPY',
|
|
538
|
+
});
|
|
539
|
+
await operation.runProvider(() => operation.client.send(command, { abortSignal: operation.signal }));
|
|
540
|
+
}
|
|
541
|
+
catch (err) {
|
|
542
|
+
console.error('Error updating metadata:', err);
|
|
543
|
+
throw err; // rethrow to allow caller to handle
|
|
544
|
+
}
|
|
545
|
+
finally {
|
|
546
|
+
operation.finish();
|
|
547
|
+
}
|
|
548
|
+
}
|
|
549
|
+
/**
|
|
550
|
+
* Move object from one path to another within the same bucket or to another bucket
|
|
551
|
+
*/
|
|
552
|
+
async fastMove(optionsArg) {
|
|
553
|
+
try {
|
|
554
|
+
const destinationBucket = optionsArg.targetBucket || this;
|
|
555
|
+
const exists = await destinationBucket.fastExists({
|
|
556
|
+
path: optionsArg.destinationPath,
|
|
557
|
+
});
|
|
558
|
+
if (exists && !optionsArg.overwrite) {
|
|
559
|
+
console.error(`Object already exists at destination path '${optionsArg.destinationPath}' in bucket '${destinationBucket.name}'.`);
|
|
560
|
+
return;
|
|
561
|
+
}
|
|
562
|
+
else if (exists && optionsArg.overwrite) {
|
|
563
|
+
console.log(`Overwriting existing object at destination path '${optionsArg.destinationPath}' in bucket '${destinationBucket.name}'.`);
|
|
564
|
+
}
|
|
565
|
+
else {
|
|
566
|
+
console.log(`Moving object to path '${optionsArg.destinationPath}' in bucket '${destinationBucket.name}'.`);
|
|
567
|
+
}
|
|
568
|
+
await this.fastCopy(optionsArg);
|
|
569
|
+
await this.fastRemove({ path: optionsArg.sourcePath });
|
|
570
|
+
console.log(`Object '${optionsArg.sourcePath}' has been successfully moved to '${optionsArg.destinationPath}' in bucket '${destinationBucket.name}'.`);
|
|
571
|
+
}
|
|
572
|
+
catch (error) {
|
|
573
|
+
console.error(`Error moving object from '${optionsArg.sourcePath}' to '${optionsArg.destinationPath}':`, error);
|
|
574
|
+
throw error;
|
|
575
|
+
}
|
|
576
|
+
}
|
|
577
|
+
/**
|
|
578
|
+
* removeObject
|
|
579
|
+
*/
|
|
580
|
+
async fastRemove(optionsArg) {
|
|
581
|
+
const operation = beginBasicBucketOperation(this, optionsArg.signal);
|
|
582
|
+
const command = new plugins.s3.DeleteObjectCommand({
|
|
583
|
+
Bucket: operation.bucketName,
|
|
584
|
+
Key: optionsArg.path,
|
|
585
|
+
});
|
|
586
|
+
try {
|
|
587
|
+
await operation.runProvider(() => operation.client.send(command, { abortSignal: operation.signal }));
|
|
588
|
+
}
|
|
589
|
+
finally {
|
|
590
|
+
operation.finish();
|
|
591
|
+
}
|
|
592
|
+
}
|
|
593
|
+
/**
|
|
594
|
+
* check whether file exists
|
|
595
|
+
* @param optionsArg
|
|
596
|
+
* @returns
|
|
597
|
+
*/
|
|
598
|
+
async fastExists(optionsArg) {
|
|
599
|
+
const operation = beginBasicBucketOperation(this, optionsArg.signal);
|
|
600
|
+
try {
|
|
601
|
+
const command = new plugins.s3.HeadObjectCommand({
|
|
602
|
+
Bucket: operation.bucketName,
|
|
603
|
+
Key: optionsArg.path,
|
|
604
|
+
});
|
|
605
|
+
await operation.runProvider(() => operation.client.send(command, { abortSignal: operation.signal }));
|
|
606
|
+
console.log(`Object '${optionsArg.path}' exists in bucket '${this.name}'.`);
|
|
607
|
+
return true;
|
|
608
|
+
}
|
|
609
|
+
catch (error) {
|
|
610
|
+
try {
|
|
611
|
+
operation.assertCurrent();
|
|
612
|
+
}
|
|
613
|
+
catch (abortError) {
|
|
614
|
+
throw abortError;
|
|
615
|
+
}
|
|
616
|
+
if (error?.name === 'NotFound') {
|
|
617
|
+
console.log(`Object '${optionsArg.path}' does not exist in bucket '${this.name}'.`);
|
|
618
|
+
return false;
|
|
619
|
+
}
|
|
620
|
+
else {
|
|
621
|
+
console.error('Error checking object existence:', error);
|
|
622
|
+
throw error; // Rethrow if it's not a NotFound error to handle unexpected issues
|
|
623
|
+
}
|
|
624
|
+
}
|
|
625
|
+
finally {
|
|
626
|
+
operation.finish();
|
|
627
|
+
}
|
|
628
|
+
}
|
|
629
|
+
/**
|
|
630
|
+
* deletes this bucket
|
|
631
|
+
*/
|
|
632
|
+
async delete() {
|
|
633
|
+
await this.smartbucketRef.storageClient.send(new plugins.s3.DeleteBucketCommand({ Bucket: this.name }));
|
|
634
|
+
}
|
|
635
|
+
async fastStat(pathDescriptor) {
|
|
636
|
+
const operation = beginBasicBucketOperation(this, pathDescriptor.signal);
|
|
637
|
+
try {
|
|
638
|
+
operation.assertCurrent();
|
|
639
|
+
const checkPath = await helpers.reducePathDescriptorToPath(pathDescriptor);
|
|
640
|
+
operation.assertCurrent();
|
|
641
|
+
const command = new plugins.s3.HeadObjectCommand({
|
|
642
|
+
Bucket: operation.bucketName,
|
|
643
|
+
Key: checkPath,
|
|
644
|
+
});
|
|
645
|
+
return await operation.runProvider(() => operation.client.send(command, { abortSignal: operation.signal }));
|
|
646
|
+
}
|
|
647
|
+
finally {
|
|
648
|
+
operation.finish();
|
|
649
|
+
}
|
|
650
|
+
}
|
|
651
|
+
async isDirectory(pathDescriptor) {
|
|
652
|
+
const checkPath = await helpers.reducePathDescriptorToPath(pathDescriptor);
|
|
653
|
+
const command = new plugins.s3.ListObjectsV2Command({
|
|
654
|
+
Bucket: this.name,
|
|
655
|
+
Prefix: checkPath,
|
|
656
|
+
Delimiter: '/',
|
|
657
|
+
});
|
|
658
|
+
const { CommonPrefixes } = await this.smartbucketRef.storageClient.send(command);
|
|
659
|
+
return !!CommonPrefixes && CommonPrefixes.length > 0;
|
|
660
|
+
}
|
|
661
|
+
async isFile(pathDescriptor) {
|
|
662
|
+
const checkPath = await helpers.reducePathDescriptorToPath(pathDescriptor);
|
|
663
|
+
const command = new plugins.s3.ListObjectsV2Command({
|
|
664
|
+
Bucket: this.name,
|
|
665
|
+
Prefix: checkPath,
|
|
666
|
+
Delimiter: '/',
|
|
667
|
+
});
|
|
668
|
+
const { Contents } = await this.smartbucketRef.storageClient.send(command);
|
|
669
|
+
return !!Contents && Contents.length > 0;
|
|
670
|
+
}
|
|
671
|
+
async getMagicBytes(optionsArg) {
|
|
672
|
+
try {
|
|
673
|
+
const command = new plugins.s3.GetObjectCommand({
|
|
674
|
+
Bucket: this.name,
|
|
675
|
+
Key: optionsArg.path,
|
|
676
|
+
Range: `bytes=0-${optionsArg.length - 1}`,
|
|
677
|
+
});
|
|
678
|
+
const response = await this.smartbucketRef.storageClient.send(command);
|
|
679
|
+
const chunks = [];
|
|
680
|
+
const stream = response.Body; // SdkStreamMixin includes readable stream
|
|
681
|
+
for await (const chunk of stream) {
|
|
682
|
+
chunks.push(chunk);
|
|
683
|
+
}
|
|
684
|
+
return Buffer.concat(chunks);
|
|
685
|
+
}
|
|
686
|
+
catch (error) {
|
|
687
|
+
console.error(`Error retrieving magic bytes from object at path '${optionsArg.path}' in bucket '${this.name}':`, error);
|
|
688
|
+
throw error;
|
|
689
|
+
}
|
|
690
|
+
}
|
|
691
|
+
// ==========================================
|
|
692
|
+
// Memory-Efficient Listing Methods (Phase 1)
|
|
693
|
+
// ==========================================
|
|
694
|
+
/**
|
|
695
|
+
* List all objects with a given prefix using async generator (memory-efficient streaming)
|
|
696
|
+
* @param prefix - Optional prefix to filter objects (default: '' for all objects)
|
|
697
|
+
* @yields Object keys one at a time
|
|
698
|
+
* @example
|
|
699
|
+
* ```ts
|
|
700
|
+
* for await (const key of bucket.listAllObjects('npm/')) {
|
|
701
|
+
* console.log(key);
|
|
702
|
+
* if (shouldStop) break; // Early exit supported
|
|
703
|
+
* }
|
|
704
|
+
* ```
|
|
705
|
+
*/
|
|
706
|
+
async *listAllObjects(prefix = '') {
|
|
707
|
+
let continuationToken;
|
|
708
|
+
do {
|
|
709
|
+
const command = new plugins.s3.ListObjectsV2Command({
|
|
710
|
+
Bucket: this.name,
|
|
711
|
+
Prefix: prefix,
|
|
712
|
+
ContinuationToken: continuationToken,
|
|
713
|
+
});
|
|
714
|
+
const response = await this.smartbucketRef.storageClient.send(command);
|
|
715
|
+
for (const obj of response.Contents || []) {
|
|
716
|
+
if (obj.Key)
|
|
717
|
+
yield obj.Key;
|
|
718
|
+
}
|
|
719
|
+
continuationToken = response.NextContinuationToken;
|
|
720
|
+
} while (continuationToken);
|
|
721
|
+
}
|
|
722
|
+
/**
|
|
723
|
+
* List all objects as an RxJS Observable (for complex reactive pipelines)
|
|
724
|
+
* @param prefix - Optional prefix to filter objects (default: '' for all objects)
|
|
725
|
+
* @returns Observable that emits object keys
|
|
726
|
+
* @example
|
|
727
|
+
* ```ts
|
|
728
|
+
* bucket.listAllObjectsObservable('npm/')
|
|
729
|
+
* .pipe(
|
|
730
|
+
* filter(key => key.endsWith('.json')),
|
|
731
|
+
* take(100)
|
|
732
|
+
* )
|
|
733
|
+
* .subscribe(key => console.log(key));
|
|
734
|
+
* ```
|
|
735
|
+
*/
|
|
736
|
+
listAllObjectsObservable(prefix = '') {
|
|
737
|
+
return new plugins.smartrx.rxjs.Observable((subscriber) => {
|
|
738
|
+
const fetchPage = async (token) => {
|
|
739
|
+
try {
|
|
740
|
+
const command = new plugins.s3.ListObjectsV2Command({
|
|
741
|
+
Bucket: this.name,
|
|
742
|
+
Prefix: prefix,
|
|
743
|
+
ContinuationToken: token,
|
|
744
|
+
});
|
|
745
|
+
const response = await this.smartbucketRef.storageClient.send(command);
|
|
746
|
+
for (const obj of response.Contents || []) {
|
|
747
|
+
if (obj.Key)
|
|
748
|
+
subscriber.next(obj.Key);
|
|
749
|
+
}
|
|
750
|
+
if (response.NextContinuationToken) {
|
|
751
|
+
await fetchPage(response.NextContinuationToken);
|
|
752
|
+
}
|
|
753
|
+
else {
|
|
754
|
+
subscriber.complete();
|
|
755
|
+
}
|
|
756
|
+
}
|
|
757
|
+
catch (error) {
|
|
758
|
+
subscriber.error(error);
|
|
759
|
+
}
|
|
760
|
+
};
|
|
761
|
+
fetchPage();
|
|
762
|
+
});
|
|
763
|
+
}
|
|
764
|
+
/**
|
|
765
|
+
* Create a cursor for manual pagination control
|
|
766
|
+
* @param prefix - Optional prefix to filter objects (default: '' for all objects)
|
|
767
|
+
* @param options - Cursor options (pageSize, etc.)
|
|
768
|
+
* @returns ListCursor instance
|
|
769
|
+
* @example
|
|
770
|
+
* ```ts
|
|
771
|
+
* const cursor = bucket.createCursor('npm/', { pageSize: 500 });
|
|
772
|
+
* while (cursor.hasMore()) {
|
|
773
|
+
* const { keys, done } = await cursor.next();
|
|
774
|
+
* console.log(`Processing ${keys.length} keys...`);
|
|
775
|
+
* }
|
|
776
|
+
* ```
|
|
777
|
+
*/
|
|
778
|
+
createCursor(prefix = '', options) {
|
|
779
|
+
return new ListCursor(this, prefix, options);
|
|
780
|
+
}
|
|
781
|
+
/**
|
|
782
|
+
* List one deletion-stable keyset page using S3 ListObjectsV2 StartAfter.
|
|
783
|
+
* This requires a general-purpose S3 provider with UTF-8 byte-ordered keys.
|
|
784
|
+
*/
|
|
785
|
+
async listObjectKeysPage(optionsArg) {
|
|
786
|
+
if (!optionsArg || typeof optionsArg !== 'object' || Array.isArray(optionsArg)) {
|
|
787
|
+
throw new TypeError('Object key page options must be a plain object');
|
|
788
|
+
}
|
|
789
|
+
const prefix = optionsArg.prefix ?? '';
|
|
790
|
+
if (typeof prefix !== 'string') {
|
|
791
|
+
throw new TypeError('Object key page prefix must be a string');
|
|
792
|
+
}
|
|
793
|
+
if (!Number.isInteger(optionsArg.limit) || optionsArg.limit < 1 || optionsArg.limit > 1_000) {
|
|
794
|
+
throw new Error('Object key page limit must be an integer from 1 to 1000');
|
|
795
|
+
}
|
|
796
|
+
if (optionsArg.startAfter !== undefined
|
|
797
|
+
&& (typeof optionsArg.startAfter !== 'string'
|
|
798
|
+
|| optionsArg.startAfter.length === 0
|
|
799
|
+
|| !optionsArg.startAfter.startsWith(prefix))) {
|
|
800
|
+
throw new Error('Object key page startAfter must be a non-empty key under the prefix');
|
|
801
|
+
}
|
|
802
|
+
const response = await this.smartbucketRef.storageClient.send(new plugins.s3.ListObjectsV2Command({
|
|
803
|
+
Bucket: this.name,
|
|
804
|
+
Prefix: prefix,
|
|
805
|
+
MaxKeys: optionsArg.limit,
|
|
806
|
+
...(optionsArg.startAfter ? { StartAfter: optionsArg.startAfter } : {}),
|
|
807
|
+
}));
|
|
808
|
+
if (typeof response.IsTruncated !== 'boolean') {
|
|
809
|
+
throw new Error('Object storage returned an invalid key page truncation flag');
|
|
810
|
+
}
|
|
811
|
+
if (response.Contents !== undefined && !Array.isArray(response.Contents)) {
|
|
812
|
+
throw new Error('Object storage returned invalid key page contents');
|
|
813
|
+
}
|
|
814
|
+
const keys = (response.Contents ?? []).map((entry) => {
|
|
815
|
+
if (!entry || typeof entry.Key !== 'string') {
|
|
816
|
+
throw new Error('Object storage returned a key page entry without a string key');
|
|
817
|
+
}
|
|
818
|
+
return entry.Key;
|
|
819
|
+
});
|
|
820
|
+
if (keys.length > optionsArg.limit) {
|
|
821
|
+
throw new Error('Object storage returned more keys than the requested page limit');
|
|
822
|
+
}
|
|
823
|
+
if (new Set(keys).size !== keys.length) {
|
|
824
|
+
throw new Error('Object storage returned duplicate keys in one page');
|
|
825
|
+
}
|
|
826
|
+
let previousKey = optionsArg.startAfter;
|
|
827
|
+
for (const key of keys) {
|
|
828
|
+
if (!key.startsWith(prefix)) {
|
|
829
|
+
throw new Error('Object storage returned a key outside the requested prefix');
|
|
830
|
+
}
|
|
831
|
+
if (previousKey !== undefined && compareUtf8ObjectKeys(key, previousKey) <= 0) {
|
|
832
|
+
throw new Error('Object storage returned keys outside strict UTF-8 byte order');
|
|
833
|
+
}
|
|
834
|
+
previousKey = key;
|
|
835
|
+
}
|
|
836
|
+
if (response.IsTruncated && keys.length === 0) {
|
|
837
|
+
throw new Error('Object storage returned an empty truncated key page');
|
|
838
|
+
}
|
|
839
|
+
return {
|
|
840
|
+
keys,
|
|
841
|
+
...(response.IsTruncated ? { nextStartAfter: keys[keys.length - 1] } : {}),
|
|
842
|
+
};
|
|
843
|
+
}
|
|
844
|
+
/**
|
|
845
|
+
* Create a watcher for monitoring bucket changes (add/modify/delete)
|
|
846
|
+
* @param options - Watcher options (prefix, pollIntervalMs, etc.)
|
|
847
|
+
* @returns BucketWatcher instance
|
|
848
|
+
* @example
|
|
849
|
+
* ```ts
|
|
850
|
+
* const watcher = bucket.createWatcher({ prefix: 'uploads/', pollIntervalMs: 3000 });
|
|
851
|
+
* watcher.changeSubject.subscribe((change) => console.log('Change:', change));
|
|
852
|
+
* await watcher.start();
|
|
853
|
+
* // ... later
|
|
854
|
+
* await watcher.stop();
|
|
855
|
+
* ```
|
|
856
|
+
*/
|
|
857
|
+
createWatcher(options) {
|
|
858
|
+
return new BucketWatcher(this, options);
|
|
859
|
+
}
|
|
860
|
+
// ==========================================
|
|
861
|
+
// High-Level Listing Helpers (Phase 2)
|
|
862
|
+
// ==========================================
|
|
863
|
+
/**
|
|
864
|
+
* Find objects matching a glob pattern (memory-efficient)
|
|
865
|
+
* @param pattern - Glob pattern (e.g., "**\/*.json", "npm/packages/*\/index.json")
|
|
866
|
+
* @yields Matching object keys
|
|
867
|
+
* @example
|
|
868
|
+
* ```ts
|
|
869
|
+
* for await (const key of bucket.findByGlob('npm/packages/*\/index.json')) {
|
|
870
|
+
* console.log('Found package index:', key);
|
|
871
|
+
* }
|
|
872
|
+
* ```
|
|
873
|
+
*/
|
|
874
|
+
async *findByGlob(pattern) {
|
|
875
|
+
const matcher = new plugins.Minimatch(pattern);
|
|
876
|
+
for await (const key of this.listAllObjects('')) {
|
|
877
|
+
if (matcher.match(key))
|
|
878
|
+
yield key;
|
|
879
|
+
}
|
|
880
|
+
}
|
|
881
|
+
/**
|
|
882
|
+
* List all objects and collect into an array (convenience method)
|
|
883
|
+
* WARNING: Loads entire result set into memory. Use listAllObjects() generator for large buckets.
|
|
884
|
+
* @param prefix - Optional prefix to filter objects (default: '' for all objects)
|
|
885
|
+
* @returns Array of all object keys
|
|
886
|
+
* @example
|
|
887
|
+
* ```ts
|
|
888
|
+
* const allKeys = await bucket.listAllObjectsArray('npm/');
|
|
889
|
+
* console.log(`Found ${allKeys.length} objects`);
|
|
890
|
+
* ```
|
|
891
|
+
*/
|
|
892
|
+
async listAllObjectsArray(prefix = '') {
|
|
893
|
+
const keys = [];
|
|
894
|
+
for await (const key of this.listAllObjects(prefix)) {
|
|
895
|
+
keys.push(key);
|
|
896
|
+
}
|
|
897
|
+
return keys;
|
|
898
|
+
}
|
|
899
|
+
async cleanAllContents() {
|
|
900
|
+
try {
|
|
901
|
+
// Define the command type explicitly
|
|
902
|
+
const listCommandInput = {
|
|
903
|
+
Bucket: this.name,
|
|
904
|
+
};
|
|
905
|
+
let isTruncated = true;
|
|
906
|
+
let continuationToken = undefined;
|
|
907
|
+
while (isTruncated) {
|
|
908
|
+
// Add the continuation token to the input if present
|
|
909
|
+
const listCommand = new plugins.s3.ListObjectsV2Command({
|
|
910
|
+
...listCommandInput,
|
|
911
|
+
ContinuationToken: continuationToken,
|
|
912
|
+
});
|
|
913
|
+
// Explicitly type the response
|
|
914
|
+
const response = await this.smartbucketRef.storageClient.send(listCommand);
|
|
915
|
+
console.log(`Cleaning contents of bucket '${this.name}': Now deleting ${response.Contents?.length} items...`);
|
|
916
|
+
if (response.Contents && response.Contents.length > 0) {
|
|
917
|
+
// Delete objects in batches, mapping each item to { Key: string }
|
|
918
|
+
const deleteCommand = new plugins.s3.DeleteObjectsCommand({
|
|
919
|
+
Bucket: this.name,
|
|
920
|
+
Delete: {
|
|
921
|
+
Objects: response.Contents.map((item) => ({ Key: item.Key })),
|
|
922
|
+
Quiet: true,
|
|
923
|
+
},
|
|
924
|
+
});
|
|
925
|
+
await this.smartbucketRef.storageClient.send(deleteCommand);
|
|
926
|
+
}
|
|
927
|
+
// Update continuation token and truncation status
|
|
928
|
+
isTruncated = response.IsTruncated || false;
|
|
929
|
+
continuationToken = response.NextContinuationToken;
|
|
930
|
+
}
|
|
931
|
+
console.log(`All contents in bucket '${this.name}' have been deleted.`);
|
|
932
|
+
}
|
|
933
|
+
catch (error) {
|
|
934
|
+
console.error(`Error cleaning contents of bucket '${this.name}':`, error);
|
|
935
|
+
throw error;
|
|
936
|
+
}
|
|
937
|
+
}
|
|
938
|
+
}
|
|
939
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xhc3Nlcy5idWNrZXQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi90cy9vYmplY3RzdG9yYWdlL2NsYXNzZXMuYnVja2V0LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLG9CQUFvQjtBQUVwQixPQUFPLEtBQUssT0FBTyxNQUFNLGNBQWMsQ0FBQztBQUN4QyxPQUFPLEtBQUssT0FBTyxNQUFNLGNBQWMsQ0FBQztBQUN4QyxPQUFPLEtBQUssVUFBVSxNQUFNLGlCQUFpQixDQUFDO0FBQzlDLE9BQU8sRUFBRSxXQUFXLEVBQUUsTUFBTSwwQkFBMEIsQ0FBQztBQUN2RCxPQUFPLEVBQUUsU0FBUyxFQUFFLE1BQU0sd0JBQXdCLENBQUM7QUFDbkQsT0FBTyxFQUFFLElBQUksRUFBRSxNQUFNLG1CQUFtQixDQUFDO0FBQ3pDLE9BQU8sRUFBRSxLQUFLLEVBQUUsTUFBTSxvQkFBb0IsQ0FBQztBQUMzQyxPQUFPLEVBQUUsVUFBVSxFQUEyQixNQUFNLHlCQUF5QixDQUFDO0FBQzlFLE9BQU8sRUFBRSxhQUFhLEVBQUUsTUFBTSxzQkFBc0IsQ0FBQztBQUNyRCxPQUFPLEVBQ0wsa0JBQWtCLElBQUksMkJBQTJCLEVBQ2pELDBCQUEwQixJQUFJLG1DQUFtQyxHQUNsRSxNQUFNLHNDQUFzQyxDQUFDO0FBQzlDLE9BQU8sRUFDTCw2QkFBNkIsSUFBSSxzQ0FBc0MsRUFDdkUsY0FBYyxJQUFJLHVCQUF1QixHQUMxQyxNQUFNLHlDQUF5QyxDQUFDO0FBQ2pELE9BQU8sRUFBRSx5QkFBeUIsRUFBRSxNQUFNLHNDQUFzQyxDQUFDO0FBYWpGLE1BQU0scUJBQXFCLEdBQUcsQ0FBQyxPQUFlLEVBQUUsUUFBZ0IsRUFBVSxFQUFFLENBQzFFLE1BQU0sQ0FBQyxPQUFPLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxPQUFPLEVBQUUsTUFBTSxDQUFDLEVBQUUsTUFBTSxDQUFDLElBQUksQ0FBQyxRQUFRLEVBQUUsTUFBTSxDQUFDLENBQUMsQ0FBQztB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
|