@hdriel/aws-utils 1.1.6 → 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/dist/index.cjs CHANGED
@@ -271,7 +271,7 @@ var LambdaUtil = class {
271
271
  var import_client_s36 = require("@aws-sdk/client-s3");
272
272
 
273
273
  // src/aws/s3/s3-stream.ts
274
- var import_pathe2 = __toESM(require("pathe"), 1);
274
+ var import_pathe2 = require("pathe");
275
275
  var import_stream = require("stream");
276
276
  var import_util = require("util");
277
277
  var import_buffer2 = require("buffer");
@@ -321,6 +321,23 @@ var getTotalSeconds = (msValue) => {
321
321
  const value = (0, import_ms.default)(msValue);
322
322
  return value / 1e3;
323
323
  };
324
+ var getUnitBytes = (bytes2, unit) => {
325
+ switch (unit == null ? void 0 : unit.toUpperCase()) {
326
+ case "KB":
327
+ return bytes2 / 1024;
328
+ case "MB":
329
+ return bytes2 / __pow(1024, 2);
330
+ case "GB":
331
+ return bytes2 / __pow(1024, 3);
332
+ case "TB":
333
+ return bytes2 / __pow(1024, 4);
334
+ case "PB":
335
+ return bytes2 / __pow(1024, 5);
336
+ case "B":
337
+ default:
338
+ return bytes2;
339
+ }
340
+ };
324
341
 
325
342
  // src/aws/s3/s3-file.ts
326
343
  var import_buffer = require("buffer");
@@ -681,7 +698,6 @@ var S3Directory = class extends S3Bucket {
681
698
  constructor(props) {
682
699
  super(props);
683
700
  }
684
- // todo: checked!
685
701
  directoryExists(directoryPath) {
686
702
  return __async(this, null, function* () {
687
703
  var _a2;
@@ -699,7 +715,6 @@ var S3Directory = class extends S3Bucket {
699
715
  }
700
716
  });
701
717
  }
702
- // todo: checked!
703
718
  createDirectory(directoryPath) {
704
719
  return __async(this, null, function* () {
705
720
  let normalizedPath = getNormalizedPath(directoryPath);
@@ -709,7 +724,6 @@ var S3Directory = class extends S3Bucket {
709
724
  return result;
710
725
  });
711
726
  }
712
- // todo: checked!
713
727
  deleteDirectory(directoryPath) {
714
728
  return __async(this, null, function* () {
715
729
  var _a2, _b, _c, _d, _e, _f, _g;
@@ -779,7 +793,6 @@ var S3Directory = class extends S3Bucket {
779
793
  };
780
794
  });
781
795
  }
782
- // todo: checked!
783
796
  directoryList(directoryPath) {
784
797
  return __async(this, null, function* () {
785
798
  var _a2;
@@ -836,7 +849,6 @@ var S3Directory = class extends S3Bucket {
836
849
  return { directories, files };
837
850
  });
838
851
  }
839
- // todo: checked!
840
852
  directoryListPaginated(_0) {
841
853
  return __async(this, arguments, function* (directoryPath, {
842
854
  pageSize = 100,
@@ -955,9 +967,9 @@ var S3File = class extends S3Directory {
955
967
  constructor(props) {
956
968
  super(props);
957
969
  }
958
- fileInfo(filePath) {
970
+ fileInfo(fileKey) {
959
971
  return __async(this, null, function* () {
960
- const normalizedKey = getNormalizedPath(filePath);
972
+ const normalizedKey = getNormalizedPath(fileKey);
961
973
  if (!normalizedKey || normalizedKey === "/") throw new Error("No file key provided");
962
974
  const command = new import_client_s34.HeadObjectCommand({ Bucket: this.bucket, Key: normalizedKey });
963
975
  const result = yield this.execute(command);
@@ -996,7 +1008,6 @@ var S3File = class extends S3Directory {
996
1008
  return files;
997
1009
  });
998
1010
  }
999
- // todo: checked!
1000
1011
  fileListPaginated(_0) {
1001
1012
  return __async(this, arguments, function* (directoryPath, {
1002
1013
  fileNamePrefix,
@@ -1052,14 +1063,13 @@ var S3File = class extends S3Directory {
1052
1063
  };
1053
1064
  });
1054
1065
  }
1055
- // todo: checked!
1056
- taggingFile(filePath, tag) {
1066
+ taggingFile(fileKey, tag) {
1057
1067
  return __async(this, null, function* () {
1058
1068
  var _a2;
1059
1069
  let normalizedKey = "";
1060
1070
  const tags = [].concat(tag);
1061
1071
  try {
1062
- normalizedKey = getNormalizedPath(filePath);
1072
+ normalizedKey = getNormalizedPath(fileKey);
1063
1073
  if (!normalizedKey || normalizedKey === "/") throw new Error("No file key provided");
1064
1074
  const command = new import_client_s34.PutObjectTaggingCommand({
1065
1075
  Bucket: this.bucket,
@@ -1074,11 +1084,10 @@ var S3File = class extends S3Directory {
1074
1084
  }
1075
1085
  });
1076
1086
  }
1077
- // todo: checked!
1078
- fileVersion(filePath) {
1087
+ fileVersion(fileKey) {
1079
1088
  return __async(this, null, function* () {
1080
1089
  var _a2, _b;
1081
- const normalizedKey = getNormalizedPath(filePath);
1090
+ const normalizedKey = getNormalizedPath(fileKey);
1082
1091
  if (!normalizedKey || normalizedKey === "/") throw new Error("No file key provided");
1083
1092
  const command = new import_client_s34.GetObjectTaggingCommand({ Bucket: this.bucket, Key: normalizedKey });
1084
1093
  const result = yield this.execute(command);
@@ -1086,11 +1095,10 @@ var S3File = class extends S3Directory {
1086
1095
  return (_b = tag == null ? void 0 : tag.Value) != null ? _b : "";
1087
1096
  });
1088
1097
  }
1089
- // todo: checked!
1090
- fileUrl(filePath, expiresIn = "15m") {
1098
+ fileUrl(fileKey, expiresIn = "15m") {
1091
1099
  return __async(this, null, function* () {
1092
1100
  var _a2;
1093
- let normalizedKey = getNormalizedPath(filePath);
1101
+ let normalizedKey = getNormalizedPath(fileKey);
1094
1102
  if (!normalizedKey || normalizedKey === "/") throw new Error("No file key provided");
1095
1103
  const expiresInSeconds = typeof expiresIn === "number" ? expiresIn : (0, import_ms2.default)(expiresIn) / 1e3;
1096
1104
  const command = new import_client_s34.GetObjectCommand({ Bucket: this.bucket, Key: normalizedKey });
@@ -1098,44 +1106,34 @@ var S3File = class extends S3Directory {
1098
1106
  expiresIn: expiresInSeconds
1099
1107
  // is using 3600 it's will expire in 1 hour (default is 900 seconds = 15 minutes)
1100
1108
  });
1101
- (_a2 = this.logger) == null ? void 0 : _a2.info(null, "generate signed file url", { url, filePath: normalizedKey, expiresIn });
1109
+ (_a2 = this.logger) == null ? void 0 : _a2.info(null, "generate signed file url", { url, fileKey: normalizedKey, expiresIn });
1102
1110
  return url;
1103
1111
  });
1104
1112
  }
1105
- sizeOf(filePath, unit = "bytes") {
1113
+ sizeOf(fileKey, unit) {
1106
1114
  return __async(this, null, function* () {
1107
1115
  var _a2, _b, _c;
1108
- const normalizedKey = getNormalizedPath(filePath);
1116
+ const normalizedKey = getNormalizedPath(fileKey);
1109
1117
  if (!normalizedKey || normalizedKey === "/") throw new Error("No file key provided");
1110
1118
  try {
1111
1119
  const command = new import_client_s34.HeadObjectCommand({ Bucket: this.bucket, Key: normalizedKey });
1112
1120
  const headObject = yield this.execute(command);
1113
1121
  const bytes2 = (_a2 = headObject.ContentLength) != null ? _a2 : 0;
1114
- switch (unit) {
1115
- case "KB":
1116
- return bytes2 / 1024;
1117
- case "MB":
1118
- return bytes2 / (1024 * 1024);
1119
- case "GB":
1120
- return bytes2 / (1024 * 1024 * 1024);
1121
- default:
1122
- return bytes2;
1123
- }
1122
+ return getUnitBytes(bytes2, unit);
1124
1123
  } catch (error) {
1125
1124
  if (error.name === "NotFound" || ((_b = error.$metadata) == null ? void 0 : _b.httpStatusCode) === 404) {
1126
- (_c = this.logger) == null ? void 0 : _c.warn(this.reqId, "File not found", { filePath: normalizedKey });
1125
+ (_c = this.logger) == null ? void 0 : _c.warn(this.reqId, "File not found", { fileKey: normalizedKey });
1127
1126
  return 0;
1128
1127
  }
1129
1128
  throw error;
1130
1129
  }
1131
1130
  });
1132
1131
  }
1133
- // todo: checked!
1134
- fileExists(filePath) {
1132
+ fileExists(fileKey) {
1135
1133
  return __async(this, null, function* () {
1136
1134
  var _a2;
1137
1135
  try {
1138
- const normalizedKey = getNormalizedPath(filePath);
1136
+ const normalizedKey = getNormalizedPath(fileKey);
1139
1137
  if (!normalizedKey || normalizedKey === "/") throw new Error("No file key provided");
1140
1138
  const command = new import_client_s34.HeadObjectCommand({ Bucket: this.bucket, Key: normalizedKey });
1141
1139
  yield this.execute(command);
@@ -1148,10 +1146,9 @@ var S3File = class extends S3Directory {
1148
1146
  }
1149
1147
  });
1150
1148
  }
1151
- // todo: checked!
1152
- fileContent(filePath, format = "buffer") {
1149
+ fileContent(fileKey, format = "buffer") {
1153
1150
  return __async(this, null, function* () {
1154
- let normalizedKey = getNormalizedPath(filePath);
1151
+ let normalizedKey = getNormalizedPath(fileKey);
1155
1152
  if (!normalizedKey || normalizedKey === "/") throw new Error("No file key provided");
1156
1153
  const command = new import_client_s34.GetObjectCommand({ Bucket: this.bucket, Key: normalizedKey });
1157
1154
  const result = yield this.execute(command);
@@ -1182,18 +1179,33 @@ var S3File = class extends S3Directory {
1182
1179
  return buffer;
1183
1180
  });
1184
1181
  }
1185
- // todo: checked!
1186
- uploadFile(_0, _1) {
1187
- return __async(this, arguments, function* (filePath, fileData, acl = "private" /* private */, version = "1.0.0") {
1188
- const normalizedKey = getNormalizedPath(filePath);
1182
+ uploadFileContent(_0, _1) {
1183
+ return __async(this, arguments, function* (fileKey, fileData, {
1184
+ acl = "private" /* private */,
1185
+ version = "1.0.0",
1186
+ prettier = true
1187
+ } = {}) {
1188
+ const normalizedKey = getNormalizedPath(fileKey);
1189
1189
  if (!normalizedKey || normalizedKey === "/") throw new Error("No file key provided");
1190
+ let body;
1191
+ if (import_buffer.Buffer.isBuffer(fileData)) {
1192
+ body = fileData;
1193
+ } else if (fileData instanceof Uint8Array) {
1194
+ body = fileData;
1195
+ } else if (fileData instanceof import_node_stream.Readable) {
1196
+ body = fileData;
1197
+ } else if (typeof fileData === "string") {
1198
+ body = fileData;
1199
+ } else {
1200
+ body = prettier ? JSON.stringify(fileData, null, 2) : JSON.stringify(fileData);
1201
+ }
1190
1202
  const upload = new import_lib_storage.Upload({
1191
1203
  client: this.s3Client,
1192
1204
  params: {
1193
1205
  Bucket: this.bucket,
1194
1206
  ACL: acl,
1195
1207
  Key: normalizedKey,
1196
- Body: fileData,
1208
+ Body: body,
1197
1209
  Tagging: `version=${version}`
1198
1210
  }
1199
1211
  });
@@ -1206,10 +1218,9 @@ var S3File = class extends S3Directory {
1206
1218
  };
1207
1219
  });
1208
1220
  }
1209
- // todo: checked!
1210
- deleteFile(filePath) {
1221
+ deleteFile(fileKey) {
1211
1222
  return __async(this, null, function* () {
1212
- const normalizedKey = getNormalizedPath(filePath);
1223
+ const normalizedKey = getNormalizedPath(fileKey);
1213
1224
  if (!normalizedKey || normalizedKey === "/") throw new Error("No file key provided");
1214
1225
  const command = new import_client_s34.DeleteObjectCommand({ Bucket: this.bucket, Key: normalizedKey });
1215
1226
  return yield this.execute(command);
@@ -1224,24 +1235,24 @@ var S3Stream = class _S3Stream extends S3File {
1224
1235
  var _b = _a2, { maxUploadFileSizeRestriction = "10GB" } = _b, props = __objRest(_b, ["maxUploadFileSizeRestriction"]);
1225
1236
  super(props);
1226
1237
  __publicField(this, "maxUploadFileSizeRestriction");
1227
- // todo: LOCALSTACK SANITY CHECKED - WORKING WELL, DON'T TOUCH!
1228
- __publicField(this, "getImageFileViewCtrl", ({
1238
+ __publicField(this, "streamImageFileCtrl", ({
1229
1239
  fileKey: _fileKey,
1230
1240
  queryField = "file",
1231
- paramField = "file",
1241
+ paramsField = "file",
1242
+ headerField = "x-fileKey",
1232
1243
  cachingAgeSeconds = "1y"
1233
1244
  } = {}) => {
1234
1245
  return (req, res, next) => __async(this, null, function* () {
1235
- var _a2, _b, _c, _d, _e, _f;
1236
- let fileKey = _fileKey || (((_a2 = req.params) == null ? void 0 : _a2[paramField]) ? decodeURIComponent((_b = req.params) == null ? void 0 : _b[paramField]) : void 0) || (((_c = req.query) == null ? void 0 : _c[queryField]) ? decodeURIComponent((_d = req.query) == null ? void 0 : _d[queryField]) : void 0);
1246
+ var _a2, _b, _c, _d, _e, _f, _g, _h;
1247
+ 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);
1237
1248
  if (!fileKey || fileKey === "/") {
1238
- (_e = this.logger) == null ? void 0 : _e.warn(req.id, "image fileKey is required");
1239
- next("image fileKey is required");
1249
+ (_g = this.logger) == null ? void 0 : _g.warn(req.id, "image fileKey is required");
1250
+ next(Error("image fileKey is required"));
1240
1251
  return;
1241
1252
  }
1242
1253
  try {
1243
1254
  const imageBuffer = yield this.fileContent(fileKey, "buffer");
1244
- const ext = import_pathe2.default.extname(fileKey).slice(1).toLowerCase();
1255
+ const ext = (0, import_pathe2.extname)(fileKey).slice(1).toLowerCase();
1245
1256
  const mimeTypeMap = {
1246
1257
  jpg: "image/jpeg",
1247
1258
  jpeg: "image/jpeg",
@@ -1258,31 +1269,31 @@ var S3Stream = class _S3Stream extends S3File {
1258
1269
  if (cachingAge) res.setHeader("Cache-Control", `public, max-age=${cachingAge}`);
1259
1270
  res.status(200).send(imageBuffer);
1260
1271
  } catch (error) {
1261
- (_f = this.logger) == null ? void 0 : _f.warn(req.id, "image fileKey not found", __spreadValues({
1272
+ (_h = this.logger) == null ? void 0 : _h.warn(req.id, "image fileKey not found", __spreadValues({
1262
1273
  fileKey
1263
1274
  }, this.localstack && { localstack: this.localstack }));
1264
- next(`Failed to retrieve image file: ${error.message}`);
1275
+ next(Error(`Failed to retrieve image file: ${error.message}`));
1265
1276
  }
1266
1277
  });
1267
1278
  });
1268
- // todo: LOCALSTACK SANITY CHECKED - WORKING WELL, DON'T TOUCH!
1269
- __publicField(this, "getPdfFileViewCtrl", ({
1279
+ __publicField(this, "streamPdfFileCtrl", ({
1270
1280
  fileKey: _fileKey,
1271
1281
  queryField = "file",
1272
- paramField = "file",
1282
+ paramsField = "file",
1283
+ headerField = "x-fileKey",
1273
1284
  cachingAgeSeconds = "1y"
1274
1285
  } = {}) => {
1275
1286
  return (req, res, next) => __async(this, null, function* () {
1276
- var _a2, _b, _c, _d, _e, _f;
1277
- let fileKey = _fileKey || (((_a2 = req.params) == null ? void 0 : _a2[paramField]) ? decodeURIComponent((_b = req.params) == null ? void 0 : _b[paramField]) : void 0) || (((_c = req.query) == null ? void 0 : _c[queryField]) ? decodeURIComponent((_d = req.query) == null ? void 0 : _d[queryField]) : void 0);
1287
+ var _a2, _b, _c, _d, _e, _f, _g, _h;
1288
+ 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);
1278
1289
  if (!fileKey) {
1279
- (_e = this.logger) == null ? void 0 : _e.warn(req.id, "pdf fileKey is required");
1280
- next("pdf fileKey is required");
1290
+ (_g = this.logger) == null ? void 0 : _g.warn(req.id, "pdf fileKey is required");
1291
+ next(Error("pdf fileKey is required"));
1281
1292
  return;
1282
1293
  }
1283
1294
  try {
1284
1295
  const fileBuffer = yield this.fileContent(fileKey, "buffer");
1285
- const ext = import_pathe2.default.extname(fileKey).slice(1).toLowerCase();
1296
+ const ext = (0, import_pathe2.extname)(fileKey).slice(1).toLowerCase();
1286
1297
  const mimeTypeMap = {
1287
1298
  pdf: "application/pdf",
1288
1299
  txt: "text/plain",
@@ -1294,17 +1305,18 @@ var S3Stream = class _S3Stream extends S3File {
1294
1305
  pptx: "application/vnd.openxmlformats-officedocument.presentationml.presentation"
1295
1306
  };
1296
1307
  const contentType = mimeTypeMap[ext] || "application/octet-stream";
1308
+ const filename = (0, import_pathe2.basename)(fileKey);
1297
1309
  res.setHeader("Content-Type", contentType);
1298
- res.setHeader("Content-Disposition", `inline; filename="${import_pathe2.default.basename(fileKey)}"`);
1310
+ res.setHeader("Content-Disposition", `inline; filename="${encodeURIComponent(filename)}"`);
1299
1311
  res.setHeader("Content-Length", fileBuffer.length);
1300
1312
  const cachingAge = !cachingAgeSeconds || typeof cachingAgeSeconds === "number" ? cachingAgeSeconds : getTotalSeconds(cachingAgeSeconds);
1301
1313
  res.setHeader("Cache-Control", `public, max-age=${cachingAge}`);
1302
1314
  res.status(200).send(fileBuffer);
1303
1315
  } catch (error) {
1304
- (_f = this.logger) == null ? void 0 : _f.warn(req.id, "pdf fileKey not found", __spreadValues({
1316
+ (_h = this.logger) == null ? void 0 : _h.warn(req.id, "pdf fileKey not found", __spreadValues({
1305
1317
  fileKey
1306
1318
  }, this.localstack && { localstack: this.localstack }));
1307
- next(`Failed to retrieve pdf file: ${error.message}`);
1319
+ next(Error(`Failed to retrieve pdf file: ${error.message}`));
1308
1320
  }
1309
1321
  });
1310
1322
  });
@@ -1333,7 +1345,6 @@ var S3Stream = class _S3Stream extends S3File {
1333
1345
  return response.Body;
1334
1346
  });
1335
1347
  }
1336
- // todo: LOCALSTACK SANITY CHECKED - WORKING WELL, DON'T TOUCH!
1337
1348
  streamVideoFile(_0) {
1338
1349
  return __async(this, arguments, function* (fileKey, {
1339
1350
  Range,
@@ -1362,7 +1373,7 @@ var S3Stream = class _S3Stream extends S3File {
1362
1373
  }
1363
1374
  };
1364
1375
  } catch (error) {
1365
- (_a2 = this.logger) == null ? void 0 : _a2.warn(this.reqId, "getS3VideoStream error", {
1376
+ (_a2 = this.logger) == null ? void 0 : _a2.warn(this.reqId, "streamVideoFile error", {
1366
1377
  Bucket: this.bucket,
1367
1378
  fileKey: normalizedKey,
1368
1379
  Range,
@@ -1372,29 +1383,39 @@ var S3Stream = class _S3Stream extends S3File {
1372
1383
  }
1373
1384
  });
1374
1385
  }
1375
- // todo: LOCALSTACK SANITY CHECKED - WORKING WELL, DON'T TOUCH!
1376
- getStreamVideoFileCtrl(_0) {
1386
+ streamVideoFileCtrl() {
1377
1387
  return __async(this, arguments, function* ({
1378
- fileKey,
1379
1388
  allowedWhitelist,
1380
- contentType = "video/mp4",
1381
- streamTimeoutMS = 3e4,
1382
- bufferMB = 5
1383
- }) {
1389
+ bufferMB = 5,
1390
+ contentType,
1391
+ fileKey: _fileKey,
1392
+ queryField = "file",
1393
+ paramsField = "file",
1394
+ headerField = "x-fileKey",
1395
+ streamTimeoutMS = 3e4
1396
+ } = {}) {
1384
1397
  return (req, res, next) => __async(this, null, function* () {
1385
- var _a2, _b, _c, _d, _e, _f;
1398
+ var _a2, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m;
1399
+ 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);
1400
+ ((_e = req.headers) == null ? void 0 : _e[headerField]) ? (_f = req.headers) == null ? void 0 : _f[headerField] : void 0;
1401
+ if (!fileKey || fileKey === "/") {
1402
+ (_g = this.logger) == null ? void 0 : _g.warn(req.id, "fileKey video stream is required");
1403
+ next(Error("fileKey video stream is required"));
1404
+ return;
1405
+ }
1386
1406
  let normalizedKey = getNormalizedPath(fileKey);
1387
1407
  if (!normalizedKey || normalizedKey === "/") throw new Error("No file key provided");
1388
- const isExists = yield this.fileExists(normalizedKey);
1389
- const fileSize = yield this.sizeOf(normalizedKey);
1390
1408
  let Range;
1391
- if (!isExists) {
1392
- next(Error(`File does not exist: "${normalizedKey}"`));
1393
- return;
1394
- }
1409
+ let fileSize;
1395
1410
  try {
1411
+ const fileInfo = yield this.fileInfo(normalizedKey);
1412
+ if (!fileInfo) {
1413
+ next(Error(`File does not exist: "${normalizedKey}"`));
1414
+ return;
1415
+ }
1416
+ fileSize = getUnitBytes(fileInfo.ContentLength);
1396
1417
  if (req.method === "HEAD") {
1397
- res.setHeader("Content-Type", contentType);
1418
+ res.setHeader("Content-Type", fileInfo.ContentType);
1398
1419
  res.setHeader("Accept-Ranges", "bytes");
1399
1420
  if (fileSize) res.setHeader("Content-Length", String(fileSize));
1400
1421
  return res.status(200).end();
@@ -1427,14 +1448,14 @@ var S3Stream = class _S3Stream extends S3File {
1427
1448
  abortSignal: abort.signal
1428
1449
  });
1429
1450
  const { body, meta } = result;
1430
- const origin = Array.isArray(allowedWhitelist) ? allowedWhitelist.includes((_a2 = req.headers.origin) != null ? _a2 : "") ? req.headers.origin : void 0 : allowedWhitelist;
1451
+ const origin = Array.isArray(allowedWhitelist) ? allowedWhitelist.includes((_h = req.headers.origin) != null ? _h : "") ? req.headers.origin : void 0 : allowedWhitelist;
1431
1452
  if (origin) {
1432
1453
  res.setHeader("Access-Control-Allow-Origin", origin);
1433
1454
  res.setHeader("Vary", "Origin");
1434
1455
  }
1435
- const finalContentType = contentType.startsWith("video/") ? contentType : `video/${contentType}`;
1436
- res.setHeader("Content-Type", (_b = meta.contentType) != null ? _b : finalContentType);
1437
- res.setHeader("Accept-Ranges", (_c = meta.acceptRanges) != null ? _c : "bytes");
1456
+ const finalContentType = (contentType == null ? void 0 : contentType.startsWith("video/")) ? contentType : `video/${contentType || "mp4"}`;
1457
+ res.setHeader("Content-Type", (_i = meta.contentType) != null ? _i : finalContentType);
1458
+ res.setHeader("Accept-Ranges", (_j = meta.acceptRanges) != null ? _j : "bytes");
1438
1459
  if (Range && meta.contentRange) {
1439
1460
  res.status(206);
1440
1461
  res.setHeader("Content-Range", meta.contentRange);
@@ -1465,11 +1486,11 @@ var S3Stream = class _S3Stream extends S3File {
1465
1486
  return;
1466
1487
  }
1467
1488
  if (!res.headersSent) {
1468
- (_f = this.logger) == null ? void 0 : _f.warn(req.id, "caught exception in stream controller", {
1469
- error: (_d = error == null ? void 0 : error.message) != null ? _d : String(error),
1489
+ (_m = this.logger) == null ? void 0 : _m.warn(req.id, "caught exception in stream controller", {
1490
+ error: (_k = error == null ? void 0 : error.message) != null ? _k : String(error),
1470
1491
  key: fileKey,
1471
1492
  url: req.originalUrl,
1472
- userId: (_e = req.user) == null ? void 0 : _e._id
1493
+ userId: (_l = req.user) == null ? void 0 : _l._id
1473
1494
  });
1474
1495
  next(error);
1475
1496
  return;
@@ -1485,14 +1506,23 @@ var S3Stream = class _S3Stream extends S3File {
1485
1506
  });
1486
1507
  });
1487
1508
  }
1488
- // todo: LOCALSTACK SANITY CHECKED - WORKING WELL, DON'T TOUCH!
1489
- getStreamFileCtrl(_0) {
1490
- return __async(this, arguments, function* (fileKey, {
1509
+ streamFileCtrl() {
1510
+ return __async(this, arguments, function* ({
1511
+ fileKey: _fileKey,
1491
1512
  filename,
1492
- forDownloading = false
1513
+ forDownloading = false,
1514
+ paramsField = "file",
1515
+ queryField = "file",
1516
+ headerField = "x-fileKey"
1493
1517
  } = {}) {
1494
1518
  return (req, res, next) => __async(this, null, function* () {
1495
- var _a2, _b;
1519
+ var _a2, _b, _c, _d, _e, _f, _g, _h, _i;
1520
+ 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);
1521
+ if (!fileKey || fileKey === "/") {
1522
+ (_g = this.logger) == null ? void 0 : _g.warn(req.id, "fileKey stream is required");
1523
+ next(Error("fileKey stream is required"));
1524
+ return;
1525
+ }
1496
1526
  const abort = new AbortController();
1497
1527
  let stream = null;
1498
1528
  const onClose = () => {
@@ -1523,7 +1553,7 @@ var S3Stream = class _S3Stream extends S3File {
1523
1553
  const fileName = filename || normalizedKey.split("/").pop() || "download";
1524
1554
  res.setHeader("Content-Type", fileInfo.ContentType || "application/octet-stream");
1525
1555
  if (forDownloading) {
1526
- res.setHeader("Content-Disposition", `attachment; filename="${fileName}"`);
1556
+ res.setHeader("Content-Disposition", `attachment; filename="${encodeURIComponent(fileName)}"`);
1527
1557
  }
1528
1558
  if (fileInfo.ContentLength) {
1529
1559
  res.setHeader("Content-Length", String(fileInfo.ContentLength));
@@ -1544,13 +1574,13 @@ var S3Stream = class _S3Stream extends S3File {
1544
1574
  } catch (error) {
1545
1575
  abort.abort();
1546
1576
  if (stream) {
1547
- (_a2 = stream.destroy) == null ? void 0 : _a2.call(stream);
1577
+ (_h = stream.destroy) == null ? void 0 : _h.call(stream);
1548
1578
  }
1549
1579
  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";
1550
1580
  if (isBenignStreamError) {
1551
1581
  return;
1552
1582
  }
1553
- (_b = this.logger) == null ? void 0 : _b.error(this.reqId, "Failed to stream file", { fileKey: normalizedKey, error });
1583
+ (_i = this.logger) == null ? void 0 : _i.error(this.reqId, "Failed to stream file", { fileKey: normalizedKey, error });
1554
1584
  if (!res.headersSent) {
1555
1585
  next(error);
1556
1586
  } else if (!res.writableEnded) {
@@ -1565,17 +1595,26 @@ var S3Stream = class _S3Stream extends S3File {
1565
1595
  });
1566
1596
  });
1567
1597
  }
1568
- // todo: LOCALSTACK SANITY CHECKED - WORKING WELL, DON'T TOUCH!
1569
- getStreamZipFileCtr(_0) {
1570
- return __async(this, arguments, function* (fileKey, {
1598
+ streamZipFileCtr() {
1599
+ return __async(this, arguments, function* ({
1600
+ fileKey: _fileKey,
1571
1601
  filename: _filename,
1602
+ queryField = "file",
1603
+ paramsField = "file",
1604
+ headerField = "x-fileKey",
1572
1605
  compressionLevel = 5
1573
1606
  } = {}) {
1574
1607
  return (req, res, next) => __async(this, null, function* () {
1575
- var _a2, _b, _c, _d, _e;
1608
+ var _a2, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l;
1576
1609
  const abort = new AbortController();
1577
1610
  const onClose = () => abort.abort();
1578
1611
  try {
1612
+ 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);
1613
+ if (!fileKey || fileKey === "/") {
1614
+ (_g = this.logger) == null ? void 0 : _g.warn(req.id, "fileKey video stream is required");
1615
+ next(Error("fileKey video stream is required"));
1616
+ return;
1617
+ }
1579
1618
  const fileKeys = [].concat(fileKey).map((fileKey2) => getNormalizedPath(fileKey2)).filter((v) => v && v !== "/");
1580
1619
  if (!fileKeys.length) {
1581
1620
  throw new Error("No file keys provided");
@@ -1583,7 +1622,7 @@ var S3Stream = class _S3Stream extends S3File {
1583
1622
  let filename = _filename || (/* @__PURE__ */ new Date()).toISOString();
1584
1623
  filename = filename.endsWith(".zip") ? filename : `${filename}.zip`;
1585
1624
  req.once("close", onClose);
1586
- (_a2 = this.logger) == null ? void 0 : _a2.info(this.reqId, "Starting parallel file download...", { fileCount: fileKeys.length });
1625
+ (_h = this.logger) == null ? void 0 : _h.info(this.reqId, "Starting parallel file download...", { fileCount: fileKeys.length });
1587
1626
  const downloadPromises = fileKeys.map((fileKey2) => __async(this, null, function* () {
1588
1627
  var _a3, _b2, _c2;
1589
1628
  try {
@@ -1633,7 +1672,7 @@ var S3Stream = class _S3Stream extends S3File {
1633
1672
  }
1634
1673
  return;
1635
1674
  }
1636
- (_b = this.logger) == null ? void 0 : _b.info(this.reqId, "All files downloaded, measuring zip size...", {
1675
+ (_i = this.logger) == null ? void 0 : _i.info(this.reqId, "All files downloaded, measuring zip size...", {
1637
1676
  fileCount: fileBuffers.length,
1638
1677
  totalSizeMB: (fileBuffers.reduce((sum, f) => sum + f.buffer.length, 0) / (1024 * 1024)).toFixed(2)
1639
1678
  });
@@ -1651,13 +1690,13 @@ var S3Stream = class _S3Stream extends S3File {
1651
1690
  req.off("close", onClose);
1652
1691
  return;
1653
1692
  }
1654
- (_c = this.logger) == null ? void 0 : _c.info(this.reqId, "Zip size calculated", {
1693
+ (_j = this.logger) == null ? void 0 : _j.info(this.reqId, "Zip size calculated", {
1655
1694
  actualZipSize,
1656
1695
  sizeMB: (actualZipSize / (1024 * 1024)).toFixed(2)
1657
1696
  });
1658
1697
  const actualArchive = (0, import_archiver.default)("zip", { zlib: { level: compressionLevel } });
1659
1698
  res.setHeader("Content-Type", "application/zip");
1660
- res.setHeader("Content-Disposition", `attachment; filename="${filename}"`);
1699
+ res.setHeader("Content-Disposition", `attachment; filename="${encodeURIComponent(filename)}"`);
1661
1700
  res.setHeader("Content-Length", String(actualZipSize));
1662
1701
  res.setHeader("Access-Control-Expose-Headers", "Content-Type, Content-Disposition, Content-Length");
1663
1702
  actualArchive.on("error", (err) => {
@@ -1674,7 +1713,7 @@ var S3Stream = class _S3Stream extends S3File {
1674
1713
  actualArchive.append(file.buffer, { name: file.name });
1675
1714
  }
1676
1715
  yield actualArchive.finalize();
1677
- (_d = this.logger) == null ? void 0 : _d.info(this.reqId, "Zip download completed", {
1716
+ (_k = this.logger) == null ? void 0 : _k.info(this.reqId, "Zip download completed", {
1678
1717
  fileCount: fileBuffers.length,
1679
1718
  totalSize: actualZipSize
1680
1719
  });
@@ -1686,7 +1725,7 @@ var S3Stream = class _S3Stream extends S3File {
1686
1725
  return;
1687
1726
  }
1688
1727
  if (!res.headersSent) {
1689
- (_e = this.logger) == null ? void 0 : _e.error(this.reqId, "Failed to create zip archive", { error });
1728
+ (_l = this.logger) == null ? void 0 : _l.error(this.reqId, "Failed to create zip archive", { error });
1690
1729
  next(error);
1691
1730
  } else if (!res.writableEnded) {
1692
1731
  try {
@@ -1703,13 +1742,13 @@ var S3Stream = class _S3Stream extends S3File {
1703
1742
  static fileFilter(types, fileExt) {
1704
1743
  const fileTypesChecker = (fileExt == null ? void 0 : fileExt.length) ? new RegExp(`\\.(${fileExt.join("|")})$`, "i") : void 0;
1705
1744
  return function(_req, file, cb) {
1706
- const fileExtension = import_pathe2.default.extname(file.originalname).substring(1);
1707
- const extname = fileTypesChecker ? fileTypesChecker.test(`.${fileExtension}`) : true;
1745
+ const fileExtension = (0, import_pathe2.extname)(file.originalname).substring(1);
1746
+ const ext = fileTypesChecker ? fileTypesChecker.test(`.${fileExtension}`) : true;
1708
1747
  const mimeType = (types == null ? void 0 : types.length) ? types.some((type) => file.mimetype.startsWith(`${type}/`)) : true;
1709
- if (mimeType && extname) {
1748
+ if (mimeType && ext) {
1710
1749
  return cb(null, true);
1711
1750
  }
1712
- const errorMsg = !extname ? `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}`;
1751
+ 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}`;
1713
1752
  return cb(new Error(errorMsg));
1714
1753
  };
1715
1754
  }
@@ -1764,7 +1803,7 @@ var S3Stream = class _S3Stream extends S3File {
1764
1803
  * Middleware for uploading a single file
1765
1804
  * Adds the uploaded file info to req.s3File
1766
1805
  */
1767
- uploadSingleFile(fieldName, directoryPath, options = {}) {
1806
+ uploadSingleFileMW(fieldName, directoryPath, options = {}) {
1768
1807
  var _a2;
1769
1808
  let normalizedPath = getNormalizedPath(directoryPath);
1770
1809
  if (normalizedPath !== "/" && directoryPath !== "" && directoryPath !== void 0) normalizedPath += "/";
@@ -1796,13 +1835,14 @@ var S3Stream = class _S3Stream extends S3File {
1796
1835
  * Middleware for uploading multiple files with the same field name
1797
1836
  * Adds the uploaded files info to req.s3Files
1798
1837
  */
1799
- uploadMultipleFiles(fieldName, directoryPath, options = {}) {
1838
+ uploadMultipleFilesMW(fieldName, directoryPath, _c = {}) {
1839
+ var _d = _c, { maxFilesCount } = _d, options = __objRest(_d, ["maxFilesCount"]);
1800
1840
  let normalizedPath = getNormalizedPath(directoryPath);
1801
1841
  if (normalizedPath !== "/" && directoryPath !== "" && directoryPath !== void 0) normalizedPath += "/";
1802
1842
  else normalizedPath = "";
1803
1843
  const upload = this.getUploadFileMW(normalizedPath, options);
1804
1844
  return (req, res, next) => {
1805
- const mw = upload.array(fieldName, options.maxFilesCount || void 0);
1845
+ const mw = upload.array(fieldName, maxFilesCount || void 0);
1806
1846
  mw(req, res, (err) => {
1807
1847
  var _a2, _b;
1808
1848
  if (err) {
@@ -1825,7 +1865,7 @@ var S3Stream = class _S3Stream extends S3File {
1825
1865
  * Middleware for uploading any files (mixed field names)
1826
1866
  * Adds the uploaded files info to req.s3AllFiles
1827
1867
  */
1828
- uploadAnyFiles(directoryPath, maxCount, options = {}) {
1868
+ uploadAnyFilesMW(directoryPath, maxCount, options = {}) {
1829
1869
  let normalizedPath = getNormalizedPath(directoryPath);
1830
1870
  if (normalizedPath !== "/" && normalizedPath !== "" && directoryPath !== void 0) normalizedPath += "/";
1831
1871
  else normalizedPath = "";
@@ -1917,7 +1957,6 @@ var S3LocalstackUtil = class extends S3Util {
1917
1957
  constructor(props) {
1918
1958
  super(__spreadProps(__spreadValues({}, props), { localstack: true }));
1919
1959
  }
1920
- // todo: checked!
1921
1960
  directoryList(directoryPath) {
1922
1961
  return __async(this, null, function* () {
1923
1962
  var _a2;
@@ -1953,7 +1992,6 @@ var S3LocalstackUtil = class extends S3Util {
1953
1992
  return { directories, files };
1954
1993
  });
1955
1994
  }
1956
- // todo: checked!
1957
1995
  directoryListPaginated(_0) {
1958
1996
  return __async(this, arguments, function* (directoryPath, {
1959
1997
  pageSize = 100,