@zucker-framework/storage 1.0.0 → 1.0.5
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 +19 -0
- package/dist/index.d.mts +135 -14
- package/dist/index.d.ts +135 -14
- package/dist/index.js +323 -25
- package/dist/index.mjs +316 -24
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -386,6 +386,7 @@ LocalFileStorage = _ts_decorate([
|
|
|
386
386
|
import { Injectable as Injectable2, Logger as Logger2 } from "@nestjs/common";
|
|
387
387
|
import { S3Client, PutObjectCommand, GetObjectCommand, DeleteObjectCommand, HeadObjectCommand, ListObjectsV2Command, CopyObjectCommand } from "@aws-sdk/client-s3";
|
|
388
388
|
import { getSignedUrl } from "@aws-sdk/s3-request-presigner";
|
|
389
|
+
import { Readable } from "stream";
|
|
389
390
|
function _ts_decorate2(decorators, target, key, desc) {
|
|
390
391
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
391
392
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") {
|
|
@@ -478,6 +479,9 @@ var S3Storage = class _S3Storage {
|
|
|
478
479
|
if (!response.Body) {
|
|
479
480
|
throw new Error("Stored object response had no body");
|
|
480
481
|
}
|
|
482
|
+
if (!(response.Body instanceof Readable)) {
|
|
483
|
+
throw new Error("Stored object response must be a Node readable stream");
|
|
484
|
+
}
|
|
481
485
|
return {
|
|
482
486
|
stream: response.Body,
|
|
483
487
|
size: response.ContentLength ?? 0
|
|
@@ -584,7 +588,8 @@ __name(encodeKeyPath, "encodeKeyPath");
|
|
|
584
588
|
// src/webdav-storage.ts
|
|
585
589
|
import { Injectable as Injectable3, Logger as Logger3 } from "@nestjs/common";
|
|
586
590
|
import * as path2 from "path";
|
|
587
|
-
import {
|
|
591
|
+
import { Transform, addAbortSignal } from "stream";
|
|
592
|
+
import { pipeline, finished } from "stream/promises";
|
|
588
593
|
function _ts_decorate3(decorators, target, key, desc) {
|
|
589
594
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
590
595
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") {
|
|
@@ -617,7 +622,7 @@ var WebDavStorage = class _WebDavStorage {
|
|
|
617
622
|
providerType = "webdav";
|
|
618
623
|
options;
|
|
619
624
|
constructor(options) {
|
|
620
|
-
if (!options.url || !options.username || !options.password) {
|
|
625
|
+
if (!options.url || !options.allowAnonymous && (!options.username || !options.password)) {
|
|
621
626
|
throw new Error("WebDAV url, username and password are required");
|
|
622
627
|
}
|
|
623
628
|
this.options = options;
|
|
@@ -644,7 +649,7 @@ var WebDavStorage = class _WebDavStorage {
|
|
|
644
649
|
const remotePath = this.resolvePath(key);
|
|
645
650
|
const parentDir = remotePath.substring(0, remotePath.lastIndexOf("/"));
|
|
646
651
|
if (parentDir && parentDir !== "/") {
|
|
647
|
-
await this.
|
|
652
|
+
await this.ensureRemoteDirectory(parentDir);
|
|
648
653
|
}
|
|
649
654
|
await client.putFileContents(remotePath, buffer, {
|
|
650
655
|
contentLength: buffer.length,
|
|
@@ -660,21 +665,87 @@ var WebDavStorage = class _WebDavStorage {
|
|
|
660
665
|
};
|
|
661
666
|
}
|
|
662
667
|
async uploadStream(stream, key, options) {
|
|
663
|
-
const
|
|
664
|
-
|
|
665
|
-
|
|
668
|
+
const controller = new AbortController();
|
|
669
|
+
const abort = /* @__PURE__ */ __name(() => controller.abort(options?.signal?.reason), "abort");
|
|
670
|
+
options?.signal?.addEventListener("abort", abort, {
|
|
671
|
+
once: true
|
|
672
|
+
});
|
|
673
|
+
if (options?.signal?.aborted) abort();
|
|
674
|
+
let size = 0;
|
|
675
|
+
const counter = new Transform({
|
|
676
|
+
transform(chunk, _encoding, callback) {
|
|
677
|
+
size += chunk.length;
|
|
678
|
+
callback(null, chunk);
|
|
679
|
+
}
|
|
680
|
+
});
|
|
681
|
+
let transfer;
|
|
682
|
+
let pumping;
|
|
683
|
+
const sourceError = /* @__PURE__ */ __name((error) => controller.abort(error), "sourceError");
|
|
684
|
+
stream.on("error", sourceError);
|
|
685
|
+
addAbortSignal(controller.signal, stream);
|
|
686
|
+
try {
|
|
687
|
+
controller.signal.throwIfAborted();
|
|
688
|
+
const client = await this.getClient();
|
|
689
|
+
const remotePath = this.resolvePath(key);
|
|
690
|
+
await this.ensureRemoteDirectory(path2.posix.dirname(remotePath), controller.signal);
|
|
691
|
+
controller.signal.throwIfAborted();
|
|
692
|
+
transfer = client.putFileContents(remotePath, counter, {
|
|
693
|
+
overwrite: true,
|
|
694
|
+
contentLength: false,
|
|
695
|
+
signal: controller.signal,
|
|
696
|
+
headers: options?.contentType ? {
|
|
697
|
+
"Content-Type": options.contentType
|
|
698
|
+
} : void 0
|
|
699
|
+
});
|
|
700
|
+
pumping = pipeline(stream, counter, {
|
|
701
|
+
signal: controller.signal
|
|
702
|
+
});
|
|
703
|
+
await Promise.all([
|
|
704
|
+
transfer,
|
|
705
|
+
pumping
|
|
706
|
+
]);
|
|
707
|
+
return {
|
|
708
|
+
key,
|
|
709
|
+
url: this.buildUrl(key),
|
|
710
|
+
size
|
|
711
|
+
};
|
|
712
|
+
} catch (error) {
|
|
713
|
+
controller.abort(error);
|
|
714
|
+
stream.destroy(error instanceof Error ? error : new Error("Storage upload failed"));
|
|
715
|
+
counter.destroy();
|
|
716
|
+
await Promise.allSettled([
|
|
717
|
+
transfer,
|
|
718
|
+
pumping,
|
|
719
|
+
finished(stream, {
|
|
720
|
+
cleanup: true
|
|
721
|
+
})
|
|
722
|
+
]);
|
|
723
|
+
throw error;
|
|
724
|
+
} finally {
|
|
725
|
+
options?.signal?.removeEventListener("abort", abort);
|
|
726
|
+
stream.off("error", sourceError);
|
|
666
727
|
}
|
|
667
|
-
return this.upload(Buffer.concat(chunks), key, options);
|
|
668
728
|
}
|
|
669
|
-
async download(key) {
|
|
729
|
+
async download(key, options) {
|
|
730
|
+
options?.signal?.throwIfAborted();
|
|
670
731
|
const client = await this.getClient();
|
|
671
732
|
const remotePath = this.resolvePath(key);
|
|
672
|
-
const stat = await client.stat(remotePath
|
|
673
|
-
|
|
674
|
-
|
|
733
|
+
const stat = await client.stat(remotePath, ...options?.signal ? [
|
|
734
|
+
{
|
|
735
|
+
signal: options.signal
|
|
736
|
+
}
|
|
737
|
+
] : []);
|
|
738
|
+
if (stat.type !== "file") throw new Error("Remote path is not a file");
|
|
739
|
+
options?.signal?.throwIfAborted();
|
|
740
|
+
const stream = client.createReadStream(remotePath, ...options?.signal ? [
|
|
741
|
+
{
|
|
742
|
+
signal: options.signal
|
|
743
|
+
}
|
|
744
|
+
] : []);
|
|
745
|
+
if (options?.signal) addAbortSignal(options.signal, stream);
|
|
675
746
|
return {
|
|
676
|
-
stream
|
|
677
|
-
size: stat.size
|
|
747
|
+
stream,
|
|
748
|
+
size: stat.size
|
|
678
749
|
};
|
|
679
750
|
}
|
|
680
751
|
async delete(key) {
|
|
@@ -699,22 +770,26 @@ var WebDavStorage = class _WebDavStorage {
|
|
|
699
770
|
async getDownloadUrl(key) {
|
|
700
771
|
return this.getPublicUrl(key);
|
|
701
772
|
}
|
|
702
|
-
async list(prefix) {
|
|
773
|
+
async list(prefix, options = {}) {
|
|
703
774
|
const client = await this.getClient();
|
|
704
775
|
const remotePath = this.resolvePath(prefix);
|
|
705
776
|
try {
|
|
706
777
|
const items = await client.getDirectoryContents(remotePath, {
|
|
707
|
-
deep: true
|
|
778
|
+
deep: options.deep ?? true
|
|
708
779
|
});
|
|
709
|
-
return items.filter((item) => item.type === "file").map((item) => ({
|
|
780
|
+
return items.filter((item) => item.type === "file" || options.includeDirectories).map((item) => ({
|
|
710
781
|
key: this.stripBasePath(item.filename),
|
|
782
|
+
type: item.type,
|
|
783
|
+
filename: item.filename,
|
|
784
|
+
basename: item.basename,
|
|
785
|
+
lastmod: item.lastmod,
|
|
711
786
|
size: item.size ?? 0,
|
|
712
787
|
lastModified: new Date(item.lastmod ?? Date.now()),
|
|
713
788
|
contentType: item.mime
|
|
714
789
|
}));
|
|
715
790
|
} catch (error) {
|
|
716
791
|
const err = error;
|
|
717
|
-
if (err.status === 404) return [];
|
|
792
|
+
if (err.status === 404 && options.missing !== "throw") return [];
|
|
718
793
|
throw error;
|
|
719
794
|
}
|
|
720
795
|
}
|
|
@@ -759,7 +834,12 @@ var WebDavStorage = class _WebDavStorage {
|
|
|
759
834
|
/**
|
|
760
835
|
* 递归创建目录
|
|
761
836
|
*/
|
|
762
|
-
|
|
837
|
+
/** Accepts a storage key, with the same traversal protection as upload. */
|
|
838
|
+
async ensureDirectory(key) {
|
|
839
|
+
return this.ensureRemoteDirectory(this.resolvePath(key));
|
|
840
|
+
}
|
|
841
|
+
async ensureRemoteDirectory(dirPath, signal) {
|
|
842
|
+
if (signal) return this.createDirectoryIfMissing(dirPath, signal);
|
|
763
843
|
const inflight = this.directoryPromises.get(dirPath);
|
|
764
844
|
if (inflight) return inflight;
|
|
765
845
|
const creation = this.createDirectoryIfMissing(dirPath);
|
|
@@ -772,21 +852,35 @@ var WebDavStorage = class _WebDavStorage {
|
|
|
772
852
|
}
|
|
773
853
|
}
|
|
774
854
|
}
|
|
775
|
-
async createDirectoryIfMissing(dirPath) {
|
|
855
|
+
async createDirectoryIfMissing(dirPath, signal) {
|
|
856
|
+
signal?.throwIfAborted();
|
|
776
857
|
const client = await this.getClient();
|
|
777
|
-
if (await client.exists(dirPath
|
|
858
|
+
if (await client.exists(dirPath, ...signal ? [
|
|
859
|
+
{
|
|
860
|
+
signal
|
|
861
|
+
}
|
|
862
|
+
] : [])) return;
|
|
778
863
|
const parent = dirPath.substring(0, dirPath.lastIndexOf("/"));
|
|
779
864
|
if (parent && parent !== "/") {
|
|
780
|
-
await this.
|
|
865
|
+
await this.ensureRemoteDirectory(parent, signal);
|
|
781
866
|
}
|
|
782
867
|
try {
|
|
783
|
-
|
|
868
|
+
signal?.throwIfAborted();
|
|
869
|
+
await client.createDirectory(dirPath, ...signal ? [
|
|
870
|
+
{
|
|
871
|
+
signal
|
|
872
|
+
}
|
|
873
|
+
] : []);
|
|
784
874
|
} catch (error) {
|
|
785
875
|
const status = error.status;
|
|
786
876
|
if ([
|
|
787
877
|
405,
|
|
788
878
|
409
|
|
789
|
-
].includes(status ?? 0) && await client.exists(dirPath
|
|
879
|
+
].includes(status ?? 0) && await client.exists(dirPath, ...signal ? [
|
|
880
|
+
{
|
|
881
|
+
signal
|
|
882
|
+
}
|
|
883
|
+
] : [])) return;
|
|
790
884
|
throw error;
|
|
791
885
|
}
|
|
792
886
|
}
|
|
@@ -1012,6 +1106,198 @@ ZuckerStorageModule = _ts_decorate5([
|
|
|
1012
1106
|
Module({})
|
|
1013
1107
|
], ZuckerStorageModule);
|
|
1014
1108
|
|
|
1109
|
+
// src/storage-url-hydrator.ts
|
|
1110
|
+
function isPlainRecord(value) {
|
|
1111
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) return false;
|
|
1112
|
+
const prototype = Object.getPrototypeOf(value);
|
|
1113
|
+
return prototype === Object.prototype || prototype === null;
|
|
1114
|
+
}
|
|
1115
|
+
__name(isPlainRecord, "isPlainRecord");
|
|
1116
|
+
async function hydrateStorageUrls(value, options) {
|
|
1117
|
+
const signedUrls = /* @__PURE__ */ new Map();
|
|
1118
|
+
const hydrate = /* @__PURE__ */ __name(async (current) => {
|
|
1119
|
+
if (Array.isArray(current)) return Promise.all(current.map(hydrate));
|
|
1120
|
+
if (!isPlainRecord(current)) return current;
|
|
1121
|
+
const entries = await Promise.all(Object.entries(current).map(async ([key2, nested]) => [
|
|
1122
|
+
key2,
|
|
1123
|
+
await hydrate(nested)
|
|
1124
|
+
]));
|
|
1125
|
+
const result = Object.fromEntries(entries);
|
|
1126
|
+
const key = result[options.storageKeyField];
|
|
1127
|
+
if (typeof key === "string" && key.length > 0 && options.allowedStorageKeys.has(key)) {
|
|
1128
|
+
let signed = signedUrls.get(key);
|
|
1129
|
+
if (!signed) {
|
|
1130
|
+
signed = options.getDownloadUrl(key);
|
|
1131
|
+
signedUrls.set(key, signed);
|
|
1132
|
+
}
|
|
1133
|
+
const url = await signed;
|
|
1134
|
+
for (const field of options.urlFields) {
|
|
1135
|
+
Object.defineProperty(result, field, {
|
|
1136
|
+
value: url,
|
|
1137
|
+
writable: true,
|
|
1138
|
+
enumerable: true,
|
|
1139
|
+
configurable: true
|
|
1140
|
+
});
|
|
1141
|
+
}
|
|
1142
|
+
}
|
|
1143
|
+
return result;
|
|
1144
|
+
}, "hydrate");
|
|
1145
|
+
return hydrate(value);
|
|
1146
|
+
}
|
|
1147
|
+
__name(hydrateStorageUrls, "hydrateStorageUrls");
|
|
1148
|
+
|
|
1149
|
+
// src/unavailable-file-manager.ts
|
|
1150
|
+
var UnavailableFileManager = class {
|
|
1151
|
+
static {
|
|
1152
|
+
__name(this, "UnavailableFileManager");
|
|
1153
|
+
}
|
|
1154
|
+
providerType;
|
|
1155
|
+
message;
|
|
1156
|
+
constructor(providerType, message = `Storage provider ${providerType} is not configured`) {
|
|
1157
|
+
this.providerType = providerType;
|
|
1158
|
+
this.message = message;
|
|
1159
|
+
}
|
|
1160
|
+
isConfigured() {
|
|
1161
|
+
return false;
|
|
1162
|
+
}
|
|
1163
|
+
unavailable() {
|
|
1164
|
+
return new Error(this.message);
|
|
1165
|
+
}
|
|
1166
|
+
upload(_buffer, _key, _options) {
|
|
1167
|
+
return Promise.reject(this.unavailable());
|
|
1168
|
+
}
|
|
1169
|
+
uploadStream(_stream, _key, _options) {
|
|
1170
|
+
return Promise.reject(this.unavailable());
|
|
1171
|
+
}
|
|
1172
|
+
download(_key) {
|
|
1173
|
+
return Promise.reject(this.unavailable());
|
|
1174
|
+
}
|
|
1175
|
+
delete(_key) {
|
|
1176
|
+
return Promise.reject(this.unavailable());
|
|
1177
|
+
}
|
|
1178
|
+
exists(_key) {
|
|
1179
|
+
return Promise.resolve(false);
|
|
1180
|
+
}
|
|
1181
|
+
getPublicUrl(_key) {
|
|
1182
|
+
return Promise.reject(this.unavailable());
|
|
1183
|
+
}
|
|
1184
|
+
getDownloadUrl(_key) {
|
|
1185
|
+
return Promise.reject(this.unavailable());
|
|
1186
|
+
}
|
|
1187
|
+
list(_prefix) {
|
|
1188
|
+
return Promise.resolve([]);
|
|
1189
|
+
}
|
|
1190
|
+
};
|
|
1191
|
+
|
|
1192
|
+
// src/verified-object-transfer.ts
|
|
1193
|
+
import { createHash } from "crypto";
|
|
1194
|
+
var StorageTransferError = class extends Error {
|
|
1195
|
+
static {
|
|
1196
|
+
__name(this, "StorageTransferError");
|
|
1197
|
+
}
|
|
1198
|
+
code;
|
|
1199
|
+
constructor(code) {
|
|
1200
|
+
super(code), this.code = code;
|
|
1201
|
+
this.name = "StorageTransferError";
|
|
1202
|
+
}
|
|
1203
|
+
};
|
|
1204
|
+
function verifyStoredObject(object, expected, detectMimeType, errorFactory = (code) => new StorageTransferError(code)) {
|
|
1205
|
+
if (object.reportedSize !== object.body.length || object.body.length !== expected.size) throw errorFactory("TARGET_SIZE_CONFLICT");
|
|
1206
|
+
if (detectMimeType(object.body) !== expected.mimeType) throw errorFactory("TARGET_MIME_CONFLICT");
|
|
1207
|
+
if (createHash("sha256").update(object.body).digest("hex") !== expected.sha256) throw errorFactory("TARGET_HASH_CONFLICT");
|
|
1208
|
+
}
|
|
1209
|
+
__name(verifyStoredObject, "verifyStoredObject");
|
|
1210
|
+
async function transferVerifiedObject(options) {
|
|
1211
|
+
const fail = options.errorFactory ?? ((code) => new StorageTransferError(code));
|
|
1212
|
+
const body = options.source.body;
|
|
1213
|
+
if (options.source.reportedSize !== body.length || body.length === 0) throw fail("SOURCE_SIZE_MISMATCH");
|
|
1214
|
+
const metadata = {
|
|
1215
|
+
sha256: createHash("sha256").update(body).digest("hex"),
|
|
1216
|
+
size: body.length,
|
|
1217
|
+
mimeType: options.detectMimeType(body)
|
|
1218
|
+
};
|
|
1219
|
+
if (await options.target.exists(options.destinationKey)) {
|
|
1220
|
+
verifyStoredObject(await options.target.read(options.destinationKey), metadata, options.detectMimeType, fail);
|
|
1221
|
+
return {
|
|
1222
|
+
...metadata,
|
|
1223
|
+
targetDisposition: options.mode === "dry-run" ? "planned" : "reused"
|
|
1224
|
+
};
|
|
1225
|
+
}
|
|
1226
|
+
if (options.mode === "dry-run" || !options.allowUpload) return {
|
|
1227
|
+
...metadata,
|
|
1228
|
+
targetDisposition: "planned"
|
|
1229
|
+
};
|
|
1230
|
+
const uploaded = await options.target.write(options.destinationKey, body, {
|
|
1231
|
+
contentType: metadata.mimeType,
|
|
1232
|
+
metadata: {
|
|
1233
|
+
sha256: metadata.sha256,
|
|
1234
|
+
size: String(metadata.size),
|
|
1235
|
+
mimeType: metadata.mimeType
|
|
1236
|
+
},
|
|
1237
|
+
private: true
|
|
1238
|
+
});
|
|
1239
|
+
if (uploaded.size !== metadata.size) throw fail("UPLOAD_SIZE_MISMATCH");
|
|
1240
|
+
verifyStoredObject(await options.target.read(options.destinationKey), metadata, options.detectMimeType, fail);
|
|
1241
|
+
return {
|
|
1242
|
+
...metadata,
|
|
1243
|
+
targetDisposition: "uploaded"
|
|
1244
|
+
};
|
|
1245
|
+
}
|
|
1246
|
+
__name(transferVerifiedObject, "transferVerifiedObject");
|
|
1247
|
+
|
|
1248
|
+
// src/buffered-file-manager-store.ts
|
|
1249
|
+
var BufferedFileManagerStore = class {
|
|
1250
|
+
static {
|
|
1251
|
+
__name(this, "BufferedFileManagerStore");
|
|
1252
|
+
}
|
|
1253
|
+
manager;
|
|
1254
|
+
maxObjectBytes;
|
|
1255
|
+
errorFactory;
|
|
1256
|
+
constructor(manager, maxObjectBytes, errorFactory = (code) => new StorageTransferError(code)) {
|
|
1257
|
+
this.manager = manager;
|
|
1258
|
+
this.maxObjectBytes = maxObjectBytes;
|
|
1259
|
+
this.errorFactory = errorFactory;
|
|
1260
|
+
if (!Number.isSafeInteger(maxObjectBytes) || maxObjectBytes < 1) throw new RangeError("maxObjectBytes must be a positive integer");
|
|
1261
|
+
if (!manager.isConfigured()) throw errorFactory("STORAGE_NOT_CONFIGURED");
|
|
1262
|
+
}
|
|
1263
|
+
async read(key) {
|
|
1264
|
+
const downloaded = await this.manager.download(key);
|
|
1265
|
+
if (downloaded.size < 1 || downloaded.size > this.maxObjectBytes) {
|
|
1266
|
+
downloaded.stream.destroy();
|
|
1267
|
+
throw this.errorFactory("OBJECT_SIZE_OUT_OF_BOUNDS");
|
|
1268
|
+
}
|
|
1269
|
+
const chunks = [];
|
|
1270
|
+
let size = 0;
|
|
1271
|
+
for await (const chunk of downloaded.stream) {
|
|
1272
|
+
const buffer = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);
|
|
1273
|
+
size += buffer.length;
|
|
1274
|
+
if (size > this.maxObjectBytes) {
|
|
1275
|
+
downloaded.stream.destroy();
|
|
1276
|
+
throw this.errorFactory("OBJECT_SIZE_OUT_OF_BOUNDS");
|
|
1277
|
+
}
|
|
1278
|
+
chunks.push(buffer);
|
|
1279
|
+
}
|
|
1280
|
+
return {
|
|
1281
|
+
body: Buffer.concat(chunks),
|
|
1282
|
+
reportedSize: downloaded.size
|
|
1283
|
+
};
|
|
1284
|
+
}
|
|
1285
|
+
exists(key) {
|
|
1286
|
+
return this.manager.exists(key);
|
|
1287
|
+
}
|
|
1288
|
+
async write(key, body, options) {
|
|
1289
|
+
if (body.length > this.maxObjectBytes) throw this.errorFactory("OBJECT_SIZE_OUT_OF_BOUNDS");
|
|
1290
|
+
const result = await this.manager.upload(body, key, {
|
|
1291
|
+
contentType: options.contentType,
|
|
1292
|
+
metadata: options.metadata,
|
|
1293
|
+
acl: "private"
|
|
1294
|
+
});
|
|
1295
|
+
return {
|
|
1296
|
+
size: result.size
|
|
1297
|
+
};
|
|
1298
|
+
}
|
|
1299
|
+
};
|
|
1300
|
+
|
|
1015
1301
|
// src/index.ts
|
|
1016
1302
|
var StorageProvider = /* @__PURE__ */ (function(StorageProvider2) {
|
|
1017
1303
|
StorageProvider2["LOCAL"] = "LOCAL";
|
|
@@ -1020,16 +1306,22 @@ var StorageProvider = /* @__PURE__ */ (function(StorageProvider2) {
|
|
|
1020
1306
|
return StorageProvider2;
|
|
1021
1307
|
})({});
|
|
1022
1308
|
export {
|
|
1309
|
+
BufferedFileManagerStore,
|
|
1023
1310
|
DANGEROUS_EXTENSIONS,
|
|
1024
1311
|
FILE_MANAGER,
|
|
1025
1312
|
FileLifecycleManager,
|
|
1026
1313
|
LocalFileStorage,
|
|
1027
1314
|
S3Storage,
|
|
1028
1315
|
StorageProvider,
|
|
1316
|
+
StorageTransferError,
|
|
1317
|
+
UnavailableFileManager,
|
|
1029
1318
|
WebDavStorage,
|
|
1030
1319
|
ZuckerStorageModule,
|
|
1031
1320
|
generateDateBasedKey,
|
|
1321
|
+
hydrateStorageUrls,
|
|
1032
1322
|
isFileDenied,
|
|
1033
1323
|
isSafeOriginalFileName,
|
|
1034
|
-
sanitizeFileName
|
|
1324
|
+
sanitizeFileName,
|
|
1325
|
+
transferVerifiedObject,
|
|
1326
|
+
verifyStoredObject
|
|
1035
1327
|
};
|