@hdriel/aws-utils 1.1.7 → 1.1.8
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 +317 -163
- package/dist/index.cjs +157 -119
- package/dist/index.d.cts +41 -23
- package/dist/index.d.ts +41 -23
- package/dist/index.js +158 -120
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -232,7 +232,7 @@ var LambdaUtil = class {
|
|
|
232
232
|
import { ListObjectsV2Command as ListObjectsV2Command4 } from "@aws-sdk/client-s3";
|
|
233
233
|
|
|
234
234
|
// src/aws/s3/s3-stream.ts
|
|
235
|
-
import
|
|
235
|
+
import { basename as basename2, extname } from "pathe";
|
|
236
236
|
import { pipeline } from "stream";
|
|
237
237
|
import { promisify } from "util";
|
|
238
238
|
import { Buffer as Buffer3 } from "buffer";
|
|
@@ -282,10 +282,27 @@ var getTotalSeconds = (msValue) => {
|
|
|
282
282
|
const value = ms(msValue);
|
|
283
283
|
return value / 1e3;
|
|
284
284
|
};
|
|
285
|
+
var getUnitBytes = (bytes2, unit) => {
|
|
286
|
+
switch (unit == null ? void 0 : unit.toUpperCase()) {
|
|
287
|
+
case "KB":
|
|
288
|
+
return bytes2 / 1024;
|
|
289
|
+
case "MB":
|
|
290
|
+
return bytes2 / __pow(1024, 2);
|
|
291
|
+
case "GB":
|
|
292
|
+
return bytes2 / __pow(1024, 3);
|
|
293
|
+
case "TB":
|
|
294
|
+
return bytes2 / __pow(1024, 4);
|
|
295
|
+
case "PB":
|
|
296
|
+
return bytes2 / __pow(1024, 5);
|
|
297
|
+
case "B":
|
|
298
|
+
default:
|
|
299
|
+
return bytes2;
|
|
300
|
+
}
|
|
301
|
+
};
|
|
285
302
|
|
|
286
303
|
// src/aws/s3/s3-file.ts
|
|
287
304
|
import { Buffer as Buffer2 } from "buffer";
|
|
288
|
-
import "stream";
|
|
305
|
+
import { Readable } from "stream";
|
|
289
306
|
import ms2 from "ms";
|
|
290
307
|
import { basename } from "pathe";
|
|
291
308
|
import { Upload } from "@aws-sdk/lib-storage";
|
|
@@ -670,7 +687,6 @@ var S3Directory = class extends S3Bucket {
|
|
|
670
687
|
constructor(props) {
|
|
671
688
|
super(props);
|
|
672
689
|
}
|
|
673
|
-
// todo: checked!
|
|
674
690
|
directoryExists(directoryPath) {
|
|
675
691
|
return __async(this, null, function* () {
|
|
676
692
|
var _a2;
|
|
@@ -688,7 +704,6 @@ var S3Directory = class extends S3Bucket {
|
|
|
688
704
|
}
|
|
689
705
|
});
|
|
690
706
|
}
|
|
691
|
-
// todo: checked!
|
|
692
707
|
createDirectory(directoryPath) {
|
|
693
708
|
return __async(this, null, function* () {
|
|
694
709
|
let normalizedPath = getNormalizedPath(directoryPath);
|
|
@@ -698,7 +713,6 @@ var S3Directory = class extends S3Bucket {
|
|
|
698
713
|
return result;
|
|
699
714
|
});
|
|
700
715
|
}
|
|
701
|
-
// todo: checked!
|
|
702
716
|
deleteDirectory(directoryPath) {
|
|
703
717
|
return __async(this, null, function* () {
|
|
704
718
|
var _a2, _b, _c, _d, _e, _f, _g;
|
|
@@ -768,7 +782,6 @@ var S3Directory = class extends S3Bucket {
|
|
|
768
782
|
};
|
|
769
783
|
});
|
|
770
784
|
}
|
|
771
|
-
// todo: checked!
|
|
772
785
|
directoryList(directoryPath) {
|
|
773
786
|
return __async(this, null, function* () {
|
|
774
787
|
var _a2;
|
|
@@ -825,7 +838,6 @@ var S3Directory = class extends S3Bucket {
|
|
|
825
838
|
return { directories, files };
|
|
826
839
|
});
|
|
827
840
|
}
|
|
828
|
-
// todo: checked!
|
|
829
841
|
directoryListPaginated(_0) {
|
|
830
842
|
return __async(this, arguments, function* (directoryPath, {
|
|
831
843
|
pageSize = 100,
|
|
@@ -944,9 +956,9 @@ var S3File = class extends S3Directory {
|
|
|
944
956
|
constructor(props) {
|
|
945
957
|
super(props);
|
|
946
958
|
}
|
|
947
|
-
fileInfo(
|
|
959
|
+
fileInfo(fileKey) {
|
|
948
960
|
return __async(this, null, function* () {
|
|
949
|
-
const normalizedKey = getNormalizedPath(
|
|
961
|
+
const normalizedKey = getNormalizedPath(fileKey);
|
|
950
962
|
if (!normalizedKey || normalizedKey === "/") throw new Error("No file key provided");
|
|
951
963
|
const command = new HeadObjectCommand2({ Bucket: this.bucket, Key: normalizedKey });
|
|
952
964
|
const result = yield this.execute(command);
|
|
@@ -985,7 +997,6 @@ var S3File = class extends S3Directory {
|
|
|
985
997
|
return files;
|
|
986
998
|
});
|
|
987
999
|
}
|
|
988
|
-
// todo: checked!
|
|
989
1000
|
fileListPaginated(_0) {
|
|
990
1001
|
return __async(this, arguments, function* (directoryPath, {
|
|
991
1002
|
fileNamePrefix,
|
|
@@ -1041,14 +1052,13 @@ var S3File = class extends S3Directory {
|
|
|
1041
1052
|
};
|
|
1042
1053
|
});
|
|
1043
1054
|
}
|
|
1044
|
-
|
|
1045
|
-
taggingFile(filePath, tag) {
|
|
1055
|
+
taggingFile(fileKey, tag) {
|
|
1046
1056
|
return __async(this, null, function* () {
|
|
1047
1057
|
var _a2;
|
|
1048
1058
|
let normalizedKey = "";
|
|
1049
1059
|
const tags = [].concat(tag);
|
|
1050
1060
|
try {
|
|
1051
|
-
normalizedKey = getNormalizedPath(
|
|
1061
|
+
normalizedKey = getNormalizedPath(fileKey);
|
|
1052
1062
|
if (!normalizedKey || normalizedKey === "/") throw new Error("No file key provided");
|
|
1053
1063
|
const command = new PutObjectTaggingCommand({
|
|
1054
1064
|
Bucket: this.bucket,
|
|
@@ -1063,11 +1073,10 @@ var S3File = class extends S3Directory {
|
|
|
1063
1073
|
}
|
|
1064
1074
|
});
|
|
1065
1075
|
}
|
|
1066
|
-
|
|
1067
|
-
fileVersion(filePath) {
|
|
1076
|
+
fileVersion(fileKey) {
|
|
1068
1077
|
return __async(this, null, function* () {
|
|
1069
1078
|
var _a2, _b;
|
|
1070
|
-
const normalizedKey = getNormalizedPath(
|
|
1079
|
+
const normalizedKey = getNormalizedPath(fileKey);
|
|
1071
1080
|
if (!normalizedKey || normalizedKey === "/") throw new Error("No file key provided");
|
|
1072
1081
|
const command = new GetObjectTaggingCommand({ Bucket: this.bucket, Key: normalizedKey });
|
|
1073
1082
|
const result = yield this.execute(command);
|
|
@@ -1075,11 +1084,10 @@ var S3File = class extends S3Directory {
|
|
|
1075
1084
|
return (_b = tag == null ? void 0 : tag.Value) != null ? _b : "";
|
|
1076
1085
|
});
|
|
1077
1086
|
}
|
|
1078
|
-
|
|
1079
|
-
fileUrl(filePath, expiresIn = "15m") {
|
|
1087
|
+
fileUrl(fileKey, expiresIn = "15m") {
|
|
1080
1088
|
return __async(this, null, function* () {
|
|
1081
1089
|
var _a2;
|
|
1082
|
-
let normalizedKey = getNormalizedPath(
|
|
1090
|
+
let normalizedKey = getNormalizedPath(fileKey);
|
|
1083
1091
|
if (!normalizedKey || normalizedKey === "/") throw new Error("No file key provided");
|
|
1084
1092
|
const expiresInSeconds = typeof expiresIn === "number" ? expiresIn : ms2(expiresIn) / 1e3;
|
|
1085
1093
|
const command = new GetObjectCommand({ Bucket: this.bucket, Key: normalizedKey });
|
|
@@ -1087,44 +1095,34 @@ var S3File = class extends S3Directory {
|
|
|
1087
1095
|
expiresIn: expiresInSeconds
|
|
1088
1096
|
// is using 3600 it's will expire in 1 hour (default is 900 seconds = 15 minutes)
|
|
1089
1097
|
});
|
|
1090
|
-
(_a2 = this.logger) == null ? void 0 : _a2.info(null, "generate signed file url", { url,
|
|
1098
|
+
(_a2 = this.logger) == null ? void 0 : _a2.info(null, "generate signed file url", { url, fileKey: normalizedKey, expiresIn });
|
|
1091
1099
|
return url;
|
|
1092
1100
|
});
|
|
1093
1101
|
}
|
|
1094
|
-
sizeOf(
|
|
1102
|
+
sizeOf(fileKey, unit) {
|
|
1095
1103
|
return __async(this, null, function* () {
|
|
1096
1104
|
var _a2, _b, _c;
|
|
1097
|
-
const normalizedKey = getNormalizedPath(
|
|
1105
|
+
const normalizedKey = getNormalizedPath(fileKey);
|
|
1098
1106
|
if (!normalizedKey || normalizedKey === "/") throw new Error("No file key provided");
|
|
1099
1107
|
try {
|
|
1100
1108
|
const command = new HeadObjectCommand2({ Bucket: this.bucket, Key: normalizedKey });
|
|
1101
1109
|
const headObject = yield this.execute(command);
|
|
1102
1110
|
const bytes2 = (_a2 = headObject.ContentLength) != null ? _a2 : 0;
|
|
1103
|
-
|
|
1104
|
-
case "KB":
|
|
1105
|
-
return bytes2 / 1024;
|
|
1106
|
-
case "MB":
|
|
1107
|
-
return bytes2 / (1024 * 1024);
|
|
1108
|
-
case "GB":
|
|
1109
|
-
return bytes2 / (1024 * 1024 * 1024);
|
|
1110
|
-
default:
|
|
1111
|
-
return bytes2;
|
|
1112
|
-
}
|
|
1111
|
+
return getUnitBytes(bytes2, unit);
|
|
1113
1112
|
} catch (error) {
|
|
1114
1113
|
if (error.name === "NotFound" || ((_b = error.$metadata) == null ? void 0 : _b.httpStatusCode) === 404) {
|
|
1115
|
-
(_c = this.logger) == null ? void 0 : _c.warn(this.reqId, "File not found", {
|
|
1114
|
+
(_c = this.logger) == null ? void 0 : _c.warn(this.reqId, "File not found", { fileKey: normalizedKey });
|
|
1116
1115
|
return 0;
|
|
1117
1116
|
}
|
|
1118
1117
|
throw error;
|
|
1119
1118
|
}
|
|
1120
1119
|
});
|
|
1121
1120
|
}
|
|
1122
|
-
|
|
1123
|
-
fileExists(filePath) {
|
|
1121
|
+
fileExists(fileKey) {
|
|
1124
1122
|
return __async(this, null, function* () {
|
|
1125
1123
|
var _a2;
|
|
1126
1124
|
try {
|
|
1127
|
-
const normalizedKey = getNormalizedPath(
|
|
1125
|
+
const normalizedKey = getNormalizedPath(fileKey);
|
|
1128
1126
|
if (!normalizedKey || normalizedKey === "/") throw new Error("No file key provided");
|
|
1129
1127
|
const command = new HeadObjectCommand2({ Bucket: this.bucket, Key: normalizedKey });
|
|
1130
1128
|
yield this.execute(command);
|
|
@@ -1137,10 +1135,9 @@ var S3File = class extends S3Directory {
|
|
|
1137
1135
|
}
|
|
1138
1136
|
});
|
|
1139
1137
|
}
|
|
1140
|
-
|
|
1141
|
-
fileContent(filePath, format = "buffer") {
|
|
1138
|
+
fileContent(fileKey, format = "buffer") {
|
|
1142
1139
|
return __async(this, null, function* () {
|
|
1143
|
-
let normalizedKey = getNormalizedPath(
|
|
1140
|
+
let normalizedKey = getNormalizedPath(fileKey);
|
|
1144
1141
|
if (!normalizedKey || normalizedKey === "/") throw new Error("No file key provided");
|
|
1145
1142
|
const command = new GetObjectCommand({ Bucket: this.bucket, Key: normalizedKey });
|
|
1146
1143
|
const result = yield this.execute(command);
|
|
@@ -1171,18 +1168,33 @@ var S3File = class extends S3Directory {
|
|
|
1171
1168
|
return buffer;
|
|
1172
1169
|
});
|
|
1173
1170
|
}
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1171
|
+
uploadFileContent(_0, _1) {
|
|
1172
|
+
return __async(this, arguments, function* (fileKey, fileData, {
|
|
1173
|
+
acl = "private" /* private */,
|
|
1174
|
+
version = "1.0.0",
|
|
1175
|
+
prettier = true
|
|
1176
|
+
} = {}) {
|
|
1177
|
+
const normalizedKey = getNormalizedPath(fileKey);
|
|
1178
1178
|
if (!normalizedKey || normalizedKey === "/") throw new Error("No file key provided");
|
|
1179
|
+
let body;
|
|
1180
|
+
if (Buffer2.isBuffer(fileData)) {
|
|
1181
|
+
body = fileData;
|
|
1182
|
+
} else if (fileData instanceof Uint8Array) {
|
|
1183
|
+
body = fileData;
|
|
1184
|
+
} else if (fileData instanceof Readable) {
|
|
1185
|
+
body = fileData;
|
|
1186
|
+
} else if (typeof fileData === "string") {
|
|
1187
|
+
body = fileData;
|
|
1188
|
+
} else {
|
|
1189
|
+
body = prettier ? JSON.stringify(fileData, null, 2) : JSON.stringify(fileData);
|
|
1190
|
+
}
|
|
1179
1191
|
const upload = new Upload({
|
|
1180
1192
|
client: this.s3Client,
|
|
1181
1193
|
params: {
|
|
1182
1194
|
Bucket: this.bucket,
|
|
1183
1195
|
ACL: acl,
|
|
1184
1196
|
Key: normalizedKey,
|
|
1185
|
-
Body:
|
|
1197
|
+
Body: body,
|
|
1186
1198
|
Tagging: `version=${version}`
|
|
1187
1199
|
}
|
|
1188
1200
|
});
|
|
@@ -1195,10 +1207,9 @@ var S3File = class extends S3Directory {
|
|
|
1195
1207
|
};
|
|
1196
1208
|
});
|
|
1197
1209
|
}
|
|
1198
|
-
|
|
1199
|
-
deleteFile(filePath) {
|
|
1210
|
+
deleteFile(fileKey) {
|
|
1200
1211
|
return __async(this, null, function* () {
|
|
1201
|
-
const normalizedKey = getNormalizedPath(
|
|
1212
|
+
const normalizedKey = getNormalizedPath(fileKey);
|
|
1202
1213
|
if (!normalizedKey || normalizedKey === "/") throw new Error("No file key provided");
|
|
1203
1214
|
const command = new DeleteObjectCommand2({ Bucket: this.bucket, Key: normalizedKey });
|
|
1204
1215
|
return yield this.execute(command);
|
|
@@ -1213,24 +1224,24 @@ var S3Stream = class _S3Stream extends S3File {
|
|
|
1213
1224
|
var _b = _a2, { maxUploadFileSizeRestriction = "10GB" } = _b, props = __objRest(_b, ["maxUploadFileSizeRestriction"]);
|
|
1214
1225
|
super(props);
|
|
1215
1226
|
__publicField(this, "maxUploadFileSizeRestriction");
|
|
1216
|
-
|
|
1217
|
-
__publicField(this, "getImageFileViewCtrl", ({
|
|
1227
|
+
__publicField(this, "streamImageFileCtrl", ({
|
|
1218
1228
|
fileKey: _fileKey,
|
|
1219
1229
|
queryField = "file",
|
|
1220
|
-
|
|
1230
|
+
paramsField = "file",
|
|
1231
|
+
headerField = "x-fileKey",
|
|
1221
1232
|
cachingAgeSeconds = "1y"
|
|
1222
1233
|
} = {}) => {
|
|
1223
1234
|
return (req, res, next) => __async(this, null, function* () {
|
|
1224
|
-
var _a2, _b, _c, _d, _e, _f;
|
|
1225
|
-
let fileKey = _fileKey || (((_a2 = req.params) == null ? void 0 : _a2[
|
|
1235
|
+
var _a2, _b, _c, _d, _e, _f, _g, _h;
|
|
1236
|
+
let fileKey = _fileKey || (((_a2 = req.params) == null ? void 0 : _a2[paramsField]) ? decodeURIComponent((_b = req.params) == null ? void 0 : _b[paramsField]) : void 0) || (((_c = req.query) == null ? void 0 : _c[queryField]) ? decodeURIComponent((_d = req.query) == null ? void 0 : _d[queryField]) : void 0) || (((_e = req.headers) == null ? void 0 : _e[headerField]) ? decodeURIComponent((_f = req.headers) == null ? void 0 : _f[headerField]) : void 0);
|
|
1226
1237
|
if (!fileKey || fileKey === "/") {
|
|
1227
|
-
(
|
|
1228
|
-
next("image fileKey is required");
|
|
1238
|
+
(_g = this.logger) == null ? void 0 : _g.warn(req.id, "image fileKey is required");
|
|
1239
|
+
next(Error("image fileKey is required"));
|
|
1229
1240
|
return;
|
|
1230
1241
|
}
|
|
1231
1242
|
try {
|
|
1232
1243
|
const imageBuffer = yield this.fileContent(fileKey, "buffer");
|
|
1233
|
-
const ext =
|
|
1244
|
+
const ext = extname(fileKey).slice(1).toLowerCase();
|
|
1234
1245
|
const mimeTypeMap = {
|
|
1235
1246
|
jpg: "image/jpeg",
|
|
1236
1247
|
jpeg: "image/jpeg",
|
|
@@ -1247,31 +1258,31 @@ var S3Stream = class _S3Stream extends S3File {
|
|
|
1247
1258
|
if (cachingAge) res.setHeader("Cache-Control", `public, max-age=${cachingAge}`);
|
|
1248
1259
|
res.status(200).send(imageBuffer);
|
|
1249
1260
|
} catch (error) {
|
|
1250
|
-
(
|
|
1261
|
+
(_h = this.logger) == null ? void 0 : _h.warn(req.id, "image fileKey not found", __spreadValues({
|
|
1251
1262
|
fileKey
|
|
1252
1263
|
}, this.localstack && { localstack: this.localstack }));
|
|
1253
|
-
next(`Failed to retrieve image file: ${error.message}`);
|
|
1264
|
+
next(Error(`Failed to retrieve image file: ${error.message}`));
|
|
1254
1265
|
}
|
|
1255
1266
|
});
|
|
1256
1267
|
});
|
|
1257
|
-
|
|
1258
|
-
__publicField(this, "getPdfFileViewCtrl", ({
|
|
1268
|
+
__publicField(this, "streamPdfFileCtrl", ({
|
|
1259
1269
|
fileKey: _fileKey,
|
|
1260
1270
|
queryField = "file",
|
|
1261
|
-
|
|
1271
|
+
paramsField = "file",
|
|
1272
|
+
headerField = "x-fileKey",
|
|
1262
1273
|
cachingAgeSeconds = "1y"
|
|
1263
1274
|
} = {}) => {
|
|
1264
1275
|
return (req, res, next) => __async(this, null, function* () {
|
|
1265
|
-
var _a2, _b, _c, _d, _e, _f;
|
|
1266
|
-
let fileKey = _fileKey || (((_a2 = req.params) == null ? void 0 : _a2[
|
|
1276
|
+
var _a2, _b, _c, _d, _e, _f, _g, _h;
|
|
1277
|
+
let fileKey = _fileKey || (((_a2 = req.params) == null ? void 0 : _a2[paramsField]) ? decodeURIComponent((_b = req.params) == null ? void 0 : _b[paramsField]) : void 0) || (((_c = req.query) == null ? void 0 : _c[queryField]) ? decodeURIComponent((_d = req.query) == null ? void 0 : _d[queryField]) : void 0) || (((_e = req.headers) == null ? void 0 : _e[headerField]) ? decodeURIComponent((_f = req.headers) == null ? void 0 : _f[headerField]) : void 0);
|
|
1267
1278
|
if (!fileKey) {
|
|
1268
|
-
(
|
|
1269
|
-
next("pdf fileKey is required");
|
|
1279
|
+
(_g = this.logger) == null ? void 0 : _g.warn(req.id, "pdf fileKey is required");
|
|
1280
|
+
next(Error("pdf fileKey is required"));
|
|
1270
1281
|
return;
|
|
1271
1282
|
}
|
|
1272
1283
|
try {
|
|
1273
1284
|
const fileBuffer = yield this.fileContent(fileKey, "buffer");
|
|
1274
|
-
const ext =
|
|
1285
|
+
const ext = extname(fileKey).slice(1).toLowerCase();
|
|
1275
1286
|
const mimeTypeMap = {
|
|
1276
1287
|
pdf: "application/pdf",
|
|
1277
1288
|
txt: "text/plain",
|
|
@@ -1283,17 +1294,18 @@ var S3Stream = class _S3Stream extends S3File {
|
|
|
1283
1294
|
pptx: "application/vnd.openxmlformats-officedocument.presentationml.presentation"
|
|
1284
1295
|
};
|
|
1285
1296
|
const contentType = mimeTypeMap[ext] || "application/octet-stream";
|
|
1297
|
+
const filename = basename2(fileKey);
|
|
1286
1298
|
res.setHeader("Content-Type", contentType);
|
|
1287
|
-
res.setHeader("Content-Disposition", `inline; filename="${
|
|
1299
|
+
res.setHeader("Content-Disposition", `inline; filename="${encodeURIComponent(filename)}"`);
|
|
1288
1300
|
res.setHeader("Content-Length", fileBuffer.length);
|
|
1289
1301
|
const cachingAge = !cachingAgeSeconds || typeof cachingAgeSeconds === "number" ? cachingAgeSeconds : getTotalSeconds(cachingAgeSeconds);
|
|
1290
1302
|
res.setHeader("Cache-Control", `public, max-age=${cachingAge}`);
|
|
1291
1303
|
res.status(200).send(fileBuffer);
|
|
1292
1304
|
} catch (error) {
|
|
1293
|
-
(
|
|
1305
|
+
(_h = this.logger) == null ? void 0 : _h.warn(req.id, "pdf fileKey not found", __spreadValues({
|
|
1294
1306
|
fileKey
|
|
1295
1307
|
}, this.localstack && { localstack: this.localstack }));
|
|
1296
|
-
next(`Failed to retrieve pdf file: ${error.message}`);
|
|
1308
|
+
next(Error(`Failed to retrieve pdf file: ${error.message}`));
|
|
1297
1309
|
}
|
|
1298
1310
|
});
|
|
1299
1311
|
});
|
|
@@ -1322,7 +1334,6 @@ var S3Stream = class _S3Stream extends S3File {
|
|
|
1322
1334
|
return response.Body;
|
|
1323
1335
|
});
|
|
1324
1336
|
}
|
|
1325
|
-
// todo: LOCALSTACK SANITY CHECKED - WORKING WELL, DON'T TOUCH!
|
|
1326
1337
|
streamVideoFile(_0) {
|
|
1327
1338
|
return __async(this, arguments, function* (fileKey, {
|
|
1328
1339
|
Range,
|
|
@@ -1351,7 +1362,7 @@ var S3Stream = class _S3Stream extends S3File {
|
|
|
1351
1362
|
}
|
|
1352
1363
|
};
|
|
1353
1364
|
} catch (error) {
|
|
1354
|
-
(_a2 = this.logger) == null ? void 0 : _a2.warn(this.reqId, "
|
|
1365
|
+
(_a2 = this.logger) == null ? void 0 : _a2.warn(this.reqId, "streamVideoFile error", {
|
|
1355
1366
|
Bucket: this.bucket,
|
|
1356
1367
|
fileKey: normalizedKey,
|
|
1357
1368
|
Range,
|
|
@@ -1361,29 +1372,39 @@ var S3Stream = class _S3Stream extends S3File {
|
|
|
1361
1372
|
}
|
|
1362
1373
|
});
|
|
1363
1374
|
}
|
|
1364
|
-
|
|
1365
|
-
getStreamVideoFileCtrl(_0) {
|
|
1375
|
+
streamVideoFileCtrl() {
|
|
1366
1376
|
return __async(this, arguments, function* ({
|
|
1367
|
-
fileKey,
|
|
1368
1377
|
allowedWhitelist,
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1378
|
+
bufferMB = 5,
|
|
1379
|
+
contentType,
|
|
1380
|
+
fileKey: _fileKey,
|
|
1381
|
+
queryField = "file",
|
|
1382
|
+
paramsField = "file",
|
|
1383
|
+
headerField = "x-fileKey",
|
|
1384
|
+
streamTimeoutMS = 3e4
|
|
1385
|
+
} = {}) {
|
|
1373
1386
|
return (req, res, next) => __async(this, null, function* () {
|
|
1374
|
-
var _a2, _b, _c, _d, _e, _f;
|
|
1387
|
+
var _a2, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m;
|
|
1388
|
+
let fileKey = _fileKey || (((_a2 = req.params) == null ? void 0 : _a2[paramsField]) ? (_b = req.params) == null ? void 0 : _b[paramsField] : void 0) || (((_c = req.query) == null ? void 0 : _c[queryField]) ? (_d = req.query) == null ? void 0 : _d[queryField] : void 0);
|
|
1389
|
+
((_e = req.headers) == null ? void 0 : _e[headerField]) ? (_f = req.headers) == null ? void 0 : _f[headerField] : void 0;
|
|
1390
|
+
if (!fileKey || fileKey === "/") {
|
|
1391
|
+
(_g = this.logger) == null ? void 0 : _g.warn(req.id, "fileKey video stream is required");
|
|
1392
|
+
next(Error("fileKey video stream is required"));
|
|
1393
|
+
return;
|
|
1394
|
+
}
|
|
1375
1395
|
let normalizedKey = getNormalizedPath(fileKey);
|
|
1376
1396
|
if (!normalizedKey || normalizedKey === "/") throw new Error("No file key provided");
|
|
1377
|
-
const isExists = yield this.fileExists(normalizedKey);
|
|
1378
|
-
const fileSize = yield this.sizeOf(normalizedKey);
|
|
1379
1397
|
let Range;
|
|
1380
|
-
|
|
1381
|
-
next(Error(`File does not exist: "${normalizedKey}"`));
|
|
1382
|
-
return;
|
|
1383
|
-
}
|
|
1398
|
+
let fileSize;
|
|
1384
1399
|
try {
|
|
1400
|
+
const fileInfo = yield this.fileInfo(normalizedKey);
|
|
1401
|
+
if (!fileInfo) {
|
|
1402
|
+
next(Error(`File does not exist: "${normalizedKey}"`));
|
|
1403
|
+
return;
|
|
1404
|
+
}
|
|
1405
|
+
fileSize = getUnitBytes(fileInfo.ContentLength);
|
|
1385
1406
|
if (req.method === "HEAD") {
|
|
1386
|
-
res.setHeader("Content-Type",
|
|
1407
|
+
res.setHeader("Content-Type", fileInfo.ContentType);
|
|
1387
1408
|
res.setHeader("Accept-Ranges", "bytes");
|
|
1388
1409
|
if (fileSize) res.setHeader("Content-Length", String(fileSize));
|
|
1389
1410
|
return res.status(200).end();
|
|
@@ -1416,14 +1437,14 @@ var S3Stream = class _S3Stream extends S3File {
|
|
|
1416
1437
|
abortSignal: abort.signal
|
|
1417
1438
|
});
|
|
1418
1439
|
const { body, meta } = result;
|
|
1419
|
-
const origin = Array.isArray(allowedWhitelist) ? allowedWhitelist.includes((
|
|
1440
|
+
const origin = Array.isArray(allowedWhitelist) ? allowedWhitelist.includes((_h = req.headers.origin) != null ? _h : "") ? req.headers.origin : void 0 : allowedWhitelist;
|
|
1420
1441
|
if (origin) {
|
|
1421
1442
|
res.setHeader("Access-Control-Allow-Origin", origin);
|
|
1422
1443
|
res.setHeader("Vary", "Origin");
|
|
1423
1444
|
}
|
|
1424
|
-
const finalContentType = contentType.startsWith("video/") ? contentType : `video/${contentType}`;
|
|
1425
|
-
res.setHeader("Content-Type", (
|
|
1426
|
-
res.setHeader("Accept-Ranges", (
|
|
1445
|
+
const finalContentType = (contentType == null ? void 0 : contentType.startsWith("video/")) ? contentType : `video/${contentType || "mp4"}`;
|
|
1446
|
+
res.setHeader("Content-Type", (_i = meta.contentType) != null ? _i : finalContentType);
|
|
1447
|
+
res.setHeader("Accept-Ranges", (_j = meta.acceptRanges) != null ? _j : "bytes");
|
|
1427
1448
|
if (Range && meta.contentRange) {
|
|
1428
1449
|
res.status(206);
|
|
1429
1450
|
res.setHeader("Content-Range", meta.contentRange);
|
|
@@ -1454,11 +1475,11 @@ var S3Stream = class _S3Stream extends S3File {
|
|
|
1454
1475
|
return;
|
|
1455
1476
|
}
|
|
1456
1477
|
if (!res.headersSent) {
|
|
1457
|
-
(
|
|
1458
|
-
error: (
|
|
1478
|
+
(_m = this.logger) == null ? void 0 : _m.warn(req.id, "caught exception in stream controller", {
|
|
1479
|
+
error: (_k = error == null ? void 0 : error.message) != null ? _k : String(error),
|
|
1459
1480
|
key: fileKey,
|
|
1460
1481
|
url: req.originalUrl,
|
|
1461
|
-
userId: (
|
|
1482
|
+
userId: (_l = req.user) == null ? void 0 : _l._id
|
|
1462
1483
|
});
|
|
1463
1484
|
next(error);
|
|
1464
1485
|
return;
|
|
@@ -1474,14 +1495,23 @@ var S3Stream = class _S3Stream extends S3File {
|
|
|
1474
1495
|
});
|
|
1475
1496
|
});
|
|
1476
1497
|
}
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1498
|
+
streamFileCtrl() {
|
|
1499
|
+
return __async(this, arguments, function* ({
|
|
1500
|
+
fileKey: _fileKey,
|
|
1480
1501
|
filename,
|
|
1481
|
-
forDownloading = false
|
|
1502
|
+
forDownloading = false,
|
|
1503
|
+
paramsField = "file",
|
|
1504
|
+
queryField = "file",
|
|
1505
|
+
headerField = "x-fileKey"
|
|
1482
1506
|
} = {}) {
|
|
1483
1507
|
return (req, res, next) => __async(this, null, function* () {
|
|
1484
|
-
var _a2, _b;
|
|
1508
|
+
var _a2, _b, _c, _d, _e, _f, _g, _h, _i;
|
|
1509
|
+
let fileKey = _fileKey || (((_a2 = req.params) == null ? void 0 : _a2[paramsField]) ? (_b = req.params) == null ? void 0 : _b[paramsField] : void 0) || (((_c = req.query) == null ? void 0 : _c[queryField]) ? (_d = req.query) == null ? void 0 : _d[queryField] : void 0) || (((_e = req.headers) == null ? void 0 : _e[headerField]) ? decodeURIComponent((_f = req.headers) == null ? void 0 : _f[headerField]) : void 0);
|
|
1510
|
+
if (!fileKey || fileKey === "/") {
|
|
1511
|
+
(_g = this.logger) == null ? void 0 : _g.warn(req.id, "fileKey stream is required");
|
|
1512
|
+
next(Error("fileKey stream is required"));
|
|
1513
|
+
return;
|
|
1514
|
+
}
|
|
1485
1515
|
const abort = new AbortController();
|
|
1486
1516
|
let stream = null;
|
|
1487
1517
|
const onClose = () => {
|
|
@@ -1512,7 +1542,7 @@ var S3Stream = class _S3Stream extends S3File {
|
|
|
1512
1542
|
const fileName = filename || normalizedKey.split("/").pop() || "download";
|
|
1513
1543
|
res.setHeader("Content-Type", fileInfo.ContentType || "application/octet-stream");
|
|
1514
1544
|
if (forDownloading) {
|
|
1515
|
-
res.setHeader("Content-Disposition", `attachment; filename="${fileName}"`);
|
|
1545
|
+
res.setHeader("Content-Disposition", `attachment; filename="${encodeURIComponent(fileName)}"`);
|
|
1516
1546
|
}
|
|
1517
1547
|
if (fileInfo.ContentLength) {
|
|
1518
1548
|
res.setHeader("Content-Length", String(fileInfo.ContentLength));
|
|
@@ -1533,13 +1563,13 @@ var S3Stream = class _S3Stream extends S3File {
|
|
|
1533
1563
|
} catch (error) {
|
|
1534
1564
|
abort.abort();
|
|
1535
1565
|
if (stream) {
|
|
1536
|
-
(
|
|
1566
|
+
(_h = stream.destroy) == null ? void 0 : _h.call(stream);
|
|
1537
1567
|
}
|
|
1538
1568
|
const isBenignStreamError = (error == null ? void 0 : error.code) === "ERR_STREAM_PREMATURE_CLOSE" || (error == null ? void 0 : error.name) === "AbortError" || (error == null ? void 0 : error.code) === "ECONNRESET";
|
|
1539
1569
|
if (isBenignStreamError) {
|
|
1540
1570
|
return;
|
|
1541
1571
|
}
|
|
1542
|
-
(
|
|
1572
|
+
(_i = this.logger) == null ? void 0 : _i.error(this.reqId, "Failed to stream file", { fileKey: normalizedKey, error });
|
|
1543
1573
|
if (!res.headersSent) {
|
|
1544
1574
|
next(error);
|
|
1545
1575
|
} else if (!res.writableEnded) {
|
|
@@ -1554,17 +1584,26 @@ var S3Stream = class _S3Stream extends S3File {
|
|
|
1554
1584
|
});
|
|
1555
1585
|
});
|
|
1556
1586
|
}
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1587
|
+
streamZipFileCtr() {
|
|
1588
|
+
return __async(this, arguments, function* ({
|
|
1589
|
+
fileKey: _fileKey,
|
|
1560
1590
|
filename: _filename,
|
|
1591
|
+
queryField = "file",
|
|
1592
|
+
paramsField = "file",
|
|
1593
|
+
headerField = "x-fileKey",
|
|
1561
1594
|
compressionLevel = 5
|
|
1562
1595
|
} = {}) {
|
|
1563
1596
|
return (req, res, next) => __async(this, null, function* () {
|
|
1564
|
-
var _a2, _b, _c, _d, _e;
|
|
1597
|
+
var _a2, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l;
|
|
1565
1598
|
const abort = new AbortController();
|
|
1566
1599
|
const onClose = () => abort.abort();
|
|
1567
1600
|
try {
|
|
1601
|
+
let fileKey = _fileKey || (((_a2 = req.params) == null ? void 0 : _a2[paramsField]) ? (_b = req.params) == null ? void 0 : _b[paramsField] : void 0) || (((_c = req.query) == null ? void 0 : _c[queryField]) ? (_d = req.query) == null ? void 0 : _d[queryField] : void 0) || (((_e = req.headers) == null ? void 0 : _e[headerField]) ? decodeURIComponent((_f = req.headers) == null ? void 0 : _f[headerField]) : void 0);
|
|
1602
|
+
if (!fileKey || fileKey === "/") {
|
|
1603
|
+
(_g = this.logger) == null ? void 0 : _g.warn(req.id, "fileKey video stream is required");
|
|
1604
|
+
next(Error("fileKey video stream is required"));
|
|
1605
|
+
return;
|
|
1606
|
+
}
|
|
1568
1607
|
const fileKeys = [].concat(fileKey).map((fileKey2) => getNormalizedPath(fileKey2)).filter((v) => v && v !== "/");
|
|
1569
1608
|
if (!fileKeys.length) {
|
|
1570
1609
|
throw new Error("No file keys provided");
|
|
@@ -1572,7 +1611,7 @@ var S3Stream = class _S3Stream extends S3File {
|
|
|
1572
1611
|
let filename = _filename || (/* @__PURE__ */ new Date()).toISOString();
|
|
1573
1612
|
filename = filename.endsWith(".zip") ? filename : `${filename}.zip`;
|
|
1574
1613
|
req.once("close", onClose);
|
|
1575
|
-
(
|
|
1614
|
+
(_h = this.logger) == null ? void 0 : _h.info(this.reqId, "Starting parallel file download...", { fileCount: fileKeys.length });
|
|
1576
1615
|
const downloadPromises = fileKeys.map((fileKey2) => __async(this, null, function* () {
|
|
1577
1616
|
var _a3, _b2, _c2;
|
|
1578
1617
|
try {
|
|
@@ -1622,7 +1661,7 @@ var S3Stream = class _S3Stream extends S3File {
|
|
|
1622
1661
|
}
|
|
1623
1662
|
return;
|
|
1624
1663
|
}
|
|
1625
|
-
(
|
|
1664
|
+
(_i = this.logger) == null ? void 0 : _i.info(this.reqId, "All files downloaded, measuring zip size...", {
|
|
1626
1665
|
fileCount: fileBuffers.length,
|
|
1627
1666
|
totalSizeMB: (fileBuffers.reduce((sum, f) => sum + f.buffer.length, 0) / (1024 * 1024)).toFixed(2)
|
|
1628
1667
|
});
|
|
@@ -1640,13 +1679,13 @@ var S3Stream = class _S3Stream extends S3File {
|
|
|
1640
1679
|
req.off("close", onClose);
|
|
1641
1680
|
return;
|
|
1642
1681
|
}
|
|
1643
|
-
(
|
|
1682
|
+
(_j = this.logger) == null ? void 0 : _j.info(this.reqId, "Zip size calculated", {
|
|
1644
1683
|
actualZipSize,
|
|
1645
1684
|
sizeMB: (actualZipSize / (1024 * 1024)).toFixed(2)
|
|
1646
1685
|
});
|
|
1647
1686
|
const actualArchive = archiver("zip", { zlib: { level: compressionLevel } });
|
|
1648
1687
|
res.setHeader("Content-Type", "application/zip");
|
|
1649
|
-
res.setHeader("Content-Disposition", `attachment; filename="${filename}"`);
|
|
1688
|
+
res.setHeader("Content-Disposition", `attachment; filename="${encodeURIComponent(filename)}"`);
|
|
1650
1689
|
res.setHeader("Content-Length", String(actualZipSize));
|
|
1651
1690
|
res.setHeader("Access-Control-Expose-Headers", "Content-Type, Content-Disposition, Content-Length");
|
|
1652
1691
|
actualArchive.on("error", (err) => {
|
|
@@ -1663,7 +1702,7 @@ var S3Stream = class _S3Stream extends S3File {
|
|
|
1663
1702
|
actualArchive.append(file.buffer, { name: file.name });
|
|
1664
1703
|
}
|
|
1665
1704
|
yield actualArchive.finalize();
|
|
1666
|
-
(
|
|
1705
|
+
(_k = this.logger) == null ? void 0 : _k.info(this.reqId, "Zip download completed", {
|
|
1667
1706
|
fileCount: fileBuffers.length,
|
|
1668
1707
|
totalSize: actualZipSize
|
|
1669
1708
|
});
|
|
@@ -1675,7 +1714,7 @@ var S3Stream = class _S3Stream extends S3File {
|
|
|
1675
1714
|
return;
|
|
1676
1715
|
}
|
|
1677
1716
|
if (!res.headersSent) {
|
|
1678
|
-
(
|
|
1717
|
+
(_l = this.logger) == null ? void 0 : _l.error(this.reqId, "Failed to create zip archive", { error });
|
|
1679
1718
|
next(error);
|
|
1680
1719
|
} else if (!res.writableEnded) {
|
|
1681
1720
|
try {
|
|
@@ -1692,13 +1731,13 @@ var S3Stream = class _S3Stream extends S3File {
|
|
|
1692
1731
|
static fileFilter(types, fileExt) {
|
|
1693
1732
|
const fileTypesChecker = (fileExt == null ? void 0 : fileExt.length) ? new RegExp(`\\.(${fileExt.join("|")})$`, "i") : void 0;
|
|
1694
1733
|
return function(_req, file, cb) {
|
|
1695
|
-
const fileExtension =
|
|
1696
|
-
const
|
|
1734
|
+
const fileExtension = extname(file.originalname).substring(1);
|
|
1735
|
+
const ext = fileTypesChecker ? fileTypesChecker.test(`.${fileExtension}`) : true;
|
|
1697
1736
|
const mimeType = (types == null ? void 0 : types.length) ? types.some((type) => file.mimetype.startsWith(`${type}/`)) : true;
|
|
1698
|
-
if (mimeType &&
|
|
1737
|
+
if (mimeType && ext) {
|
|
1699
1738
|
return cb(null, true);
|
|
1700
1739
|
}
|
|
1701
|
-
const errorMsg = !
|
|
1740
|
+
const errorMsg = !ext ? `Upload File Ext Error: Allowed extensions: [${fileExt == null ? void 0 : fileExt.join(", ")}]. Got: ${fileExtension}` : `Upload File Type Error: Allowed types: [${types == null ? void 0 : types.join(", ")}]. Got: ${file.mimetype}`;
|
|
1702
1741
|
return cb(new Error(errorMsg));
|
|
1703
1742
|
};
|
|
1704
1743
|
}
|
|
@@ -1753,7 +1792,7 @@ var S3Stream = class _S3Stream extends S3File {
|
|
|
1753
1792
|
* Middleware for uploading a single file
|
|
1754
1793
|
* Adds the uploaded file info to req.s3File
|
|
1755
1794
|
*/
|
|
1756
|
-
|
|
1795
|
+
uploadSingleFileMW(fieldName, directoryPath, options = {}) {
|
|
1757
1796
|
var _a2;
|
|
1758
1797
|
let normalizedPath = getNormalizedPath(directoryPath);
|
|
1759
1798
|
if (normalizedPath !== "/" && directoryPath !== "" && directoryPath !== void 0) normalizedPath += "/";
|
|
@@ -1785,13 +1824,14 @@ var S3Stream = class _S3Stream extends S3File {
|
|
|
1785
1824
|
* Middleware for uploading multiple files with the same field name
|
|
1786
1825
|
* Adds the uploaded files info to req.s3Files
|
|
1787
1826
|
*/
|
|
1788
|
-
|
|
1827
|
+
uploadMultipleFilesMW(fieldName, directoryPath, _c = {}) {
|
|
1828
|
+
var _d = _c, { maxFilesCount } = _d, options = __objRest(_d, ["maxFilesCount"]);
|
|
1789
1829
|
let normalizedPath = getNormalizedPath(directoryPath);
|
|
1790
1830
|
if (normalizedPath !== "/" && directoryPath !== "" && directoryPath !== void 0) normalizedPath += "/";
|
|
1791
1831
|
else normalizedPath = "";
|
|
1792
1832
|
const upload = this.getUploadFileMW(normalizedPath, options);
|
|
1793
1833
|
return (req, res, next) => {
|
|
1794
|
-
const mw = upload.array(fieldName,
|
|
1834
|
+
const mw = upload.array(fieldName, maxFilesCount || void 0);
|
|
1795
1835
|
mw(req, res, (err) => {
|
|
1796
1836
|
var _a2, _b;
|
|
1797
1837
|
if (err) {
|
|
@@ -1814,7 +1854,7 @@ var S3Stream = class _S3Stream extends S3File {
|
|
|
1814
1854
|
* Middleware for uploading any files (mixed field names)
|
|
1815
1855
|
* Adds the uploaded files info to req.s3AllFiles
|
|
1816
1856
|
*/
|
|
1817
|
-
|
|
1857
|
+
uploadAnyFilesMW(directoryPath, maxCount, options = {}) {
|
|
1818
1858
|
let normalizedPath = getNormalizedPath(directoryPath);
|
|
1819
1859
|
if (normalizedPath !== "/" && normalizedPath !== "" && directoryPath !== void 0) normalizedPath += "/";
|
|
1820
1860
|
else normalizedPath = "";
|
|
@@ -1906,7 +1946,6 @@ var S3LocalstackUtil = class extends S3Util {
|
|
|
1906
1946
|
constructor(props) {
|
|
1907
1947
|
super(__spreadProps(__spreadValues({}, props), { localstack: true }));
|
|
1908
1948
|
}
|
|
1909
|
-
// todo: checked!
|
|
1910
1949
|
directoryList(directoryPath) {
|
|
1911
1950
|
return __async(this, null, function* () {
|
|
1912
1951
|
var _a2;
|
|
@@ -1942,7 +1981,6 @@ var S3LocalstackUtil = class extends S3Util {
|
|
|
1942
1981
|
return { directories, files };
|
|
1943
1982
|
});
|
|
1944
1983
|
}
|
|
1945
|
-
// todo: checked!
|
|
1946
1984
|
directoryListPaginated(_0) {
|
|
1947
1985
|
return __async(this, arguments, function* (directoryPath, {
|
|
1948
1986
|
pageSize = 100,
|