@hot-updater/aws 0.33.0 → 0.33.2

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.mjs CHANGED
@@ -1,13 +1,13 @@
1
1
  import { CloudFrontClient, CreateInvalidationCommand, GetInvalidationCommand } from "@aws-sdk/client-cloudfront";
2
- import { DeleteObjectCommand, DeleteObjectsCommand, GetObjectCommand, HeadObjectCommand, ListObjectsV2Command, NoSuchKey, S3Client } from "@aws-sdk/client-s3";
3
- import { Upload } from "@aws-sdk/lib-storage";
2
+ import { DeleteObjectCommand, DeleteObjectsCommand, GetObjectCommand, HeadObjectCommand, ListObjectsV2Command, NoSuchKey, PutObjectCommand, S3Client } from "@aws-sdk/client-s3";
4
3
  import { createBlobDatabasePlugin, createStorageKeyBuilder, createUniversalStoragePlugin, getContentType, parseStorageUri } from "@hot-updater/plugin-core";
5
4
  import fs from "fs/promises";
6
5
  import path from "path";
6
+ import { Upload } from "@aws-sdk/lib-storage";
7
7
  import { getSignedUrl } from "@aws-sdk/s3-request-presigner";
8
8
  import { SSM } from "@aws-sdk/client-ssm";
9
9
  import { getSignedUrl as getSignedUrl$1 } from "@aws-sdk/cloudfront-signer";
10
- //#region ../../node_modules/.pnpm/mime@4.0.4/node_modules/mime/dist/types/other.js
10
+ //#region ../../node_modules/.pnpm/mime@4.1.0/node_modules/mime/dist/types/other.js
11
11
  const types$1 = {
12
12
  "application/prs.cww": ["cww"],
13
13
  "application/prs.xsf+xml": ["xsf"],
@@ -46,6 +46,7 @@ const types$1 = {
46
46
  "application/vnd.aristanetworks.swi": ["swi"],
47
47
  "application/vnd.astraea-software.iota": ["iota"],
48
48
  "application/vnd.audiograph": ["aep"],
49
+ "application/vnd.autodesk.fbx": ["fbx"],
49
50
  "application/vnd.balsamiq.bmml+xml": ["bmml"],
50
51
  "application/vnd.blueice.multipass": ["mpm"],
51
52
  "application/vnd.bmi": ["bmi"],
@@ -81,6 +82,7 @@ const types$1 = {
81
82
  "application/vnd.dart": ["dart"],
82
83
  "application/vnd.data-vision.rdz": ["rdz"],
83
84
  "application/vnd.dbf": ["dbf"],
85
+ "application/vnd.dcmp+xml": ["dcmp"],
84
86
  "application/vnd.dece.data": [
85
87
  "uvf",
86
88
  "uvvf",
@@ -134,6 +136,7 @@ const types$1 = {
134
136
  "application/vnd.fuzzysheet": ["fzs"],
135
137
  "application/vnd.genomatix.tuxedo": ["txd"],
136
138
  "application/vnd.geogebra.file": ["ggb"],
139
+ "application/vnd.geogebra.slides": ["ggs"],
137
140
  "application/vnd.geogebra.tool": ["ggt"],
138
141
  "application/vnd.geometry-explorer": ["gex", "gre"],
139
142
  "application/vnd.geonext": ["gxt"],
@@ -141,10 +144,17 @@ const types$1 = {
141
144
  "application/vnd.geospace": ["g3w"],
142
145
  "application/vnd.gmx": ["gmx"],
143
146
  "application/vnd.google-apps.document": ["gdoc"],
147
+ "application/vnd.google-apps.drawing": ["gdraw"],
148
+ "application/vnd.google-apps.form": ["gform"],
149
+ "application/vnd.google-apps.jam": ["gjam"],
150
+ "application/vnd.google-apps.map": ["gmap"],
144
151
  "application/vnd.google-apps.presentation": ["gslides"],
152
+ "application/vnd.google-apps.script": ["gscript"],
153
+ "application/vnd.google-apps.site": ["gsite"],
145
154
  "application/vnd.google-apps.spreadsheet": ["gsheet"],
146
155
  "application/vnd.google-earth.kml+xml": ["kml"],
147
156
  "application/vnd.google-earth.kmz": ["kmz"],
157
+ "application/vnd.gov.sk.xmldatacontainer+xml": ["xdcf"],
148
158
  "application/vnd.grafeq": ["gqf", "gqs"],
149
159
  "application/vnd.groove-account": ["gac"],
150
160
  "application/vnd.groove-help": ["ghf"],
@@ -271,6 +281,7 @@ const types$1 = {
271
281
  "application/vnd.ms-powerpoint.slideshow.macroenabled.12": ["ppsm"],
272
282
  "application/vnd.ms-powerpoint.template.macroenabled.12": ["potm"],
273
283
  "application/vnd.ms-project": ["*mpp", "mpt"],
284
+ "application/vnd.ms-visio.viewer": ["vdx"],
274
285
  "application/vnd.ms-word.document.macroenabled.12": ["docm"],
275
286
  "application/vnd.ms-word.template.macroenabled.12": ["dotm"],
276
287
  "application/vnd.ms-works": [
@@ -285,6 +296,7 @@ const types$1 = {
285
296
  "application/vnd.musician": ["mus"],
286
297
  "application/vnd.muvee.style": ["msty"],
287
298
  "application/vnd.mynfc": ["taglet"],
299
+ "application/vnd.nato.bindingdataobject+xml": ["bdo"],
288
300
  "application/vnd.neurolanguage.nlu": ["nlu"],
289
301
  "application/vnd.nitf": ["ntf", "nitf"],
290
302
  "application/vnd.noblenet-directory": ["nnd"],
@@ -344,6 +356,9 @@ const types$1 = {
344
356
  "application/vnd.pocketlearn": ["plf"],
345
357
  "application/vnd.powerbuilder6": ["pbd"],
346
358
  "application/vnd.previewsystems.box": ["box"],
359
+ "application/vnd.procrate.brushset": ["brushset"],
360
+ "application/vnd.procreate.brush": ["brush"],
361
+ "application/vnd.procreate.dream": ["drm"],
347
362
  "application/vnd.proteus.magazine": ["mgz"],
348
363
  "application/vnd.publishare-delta-tree": ["qps"],
349
364
  "application/vnd.pvi.ptid1": ["ptid"],
@@ -427,7 +442,9 @@ const types$1 = {
427
442
  "vsd",
428
443
  "vst",
429
444
  "vss",
430
- "vsw"
445
+ "vsw",
446
+ "vsdx",
447
+ "vtx"
431
448
  ],
432
449
  "application/vnd.visionary": ["vis"],
433
450
  "application/vnd.vsf": ["vsf"],
@@ -467,6 +484,7 @@ const types$1 = {
467
484
  "application/x-bcpio": ["bcpio"],
468
485
  "application/x-bdoc": ["*bdoc"],
469
486
  "application/x-bittorrent": ["torrent"],
487
+ "application/x-blender": ["blend"],
470
488
  "application/x-blorb": ["blb", "blorb"],
471
489
  "application/x-bzip": ["bz"],
472
490
  "application/x-bzip2": ["bz2", "boz"],
@@ -483,6 +501,7 @@ const types$1 = {
483
501
  "application/x-chess-pgn": ["pgn"],
484
502
  "application/x-chrome-extension": ["crx"],
485
503
  "application/x-cocoa": ["cco"],
504
+ "application/x-compressed": ["*rar"],
486
505
  "application/x-conference": ["nsc"],
487
506
  "application/x-cpio": ["cpio"],
488
507
  "application/x-csh": ["csh"],
@@ -527,6 +546,7 @@ const types$1 = {
527
546
  "application/x-hdf": ["hdf"],
528
547
  "application/x-httpd-php": ["php"],
529
548
  "application/x-install-instructions": ["install"],
549
+ "application/x-ipynb+json": ["ipynb"],
530
550
  "application/x-iso9660-image": ["*iso"],
531
551
  "application/x-iwork-keynote-sffkey": ["*key"],
532
552
  "application/x-iwork-numbers-sffnumbers": ["*numbers"],
@@ -623,6 +643,7 @@ const types$1 = {
623
643
  "application/x-xliff+xml": ["*xlf"],
624
644
  "application/x-xpinstall": ["xpi"],
625
645
  "application/x-xz": ["xz"],
646
+ "application/x-zip-compressed": ["*zip"],
626
647
  "application/x-zmachine": [
627
648
  "z1",
628
649
  "z2",
@@ -671,6 +692,7 @@ const types$1 = {
671
692
  "image/prs.pti": ["pti"],
672
693
  "image/vnd.adobe.photoshop": ["psd"],
673
694
  "image/vnd.airzip.accelerator.azv": ["azv"],
695
+ "image/vnd.blockfact.facti": ["facti"],
674
696
  "image/vnd.dece.graphic": [
675
697
  "uvi",
676
698
  "uvvi",
@@ -698,6 +720,7 @@ const types$1 = {
698
720
  "image/vnd.xiff": ["xif"],
699
721
  "image/vnd.zbrush.pcx": ["pcx"],
700
722
  "image/x-3ds": ["3ds"],
723
+ "image/x-adobe-dng": ["dng"],
701
724
  "image/x-cmu-raster": ["ras"],
702
725
  "image/x-cmx": ["cmx"],
703
726
  "image/x-freehand": [
@@ -723,12 +746,13 @@ const types$1 = {
723
746
  "image/x-xpixmap": ["xpm"],
724
747
  "image/x-xwindowdump": ["xwd"],
725
748
  "message/vnd.wfa.wsc": ["wsc"],
749
+ "model/vnd.bary": ["bary"],
726
750
  "model/vnd.cld": ["cld"],
727
751
  "model/vnd.collada+xml": ["dae"],
728
752
  "model/vnd.dwf": ["dwf"],
729
753
  "model/vnd.gdl": ["gdl"],
730
754
  "model/vnd.gtw": ["gtw"],
731
- "model/vnd.mts": ["mts"],
755
+ "model/vnd.mts": ["*mts"],
732
756
  "model/vnd.opengex": ["ogex"],
733
757
  "model/vnd.parasolid.transmit.binary": ["x_b"],
734
758
  "model/vnd.parasolid.transmit.text": ["x_t"],
@@ -821,7 +845,7 @@ const types$1 = {
821
845
  };
822
846
  Object.freeze(types$1);
823
847
  //#endregion
824
- //#region ../../node_modules/.pnpm/mime@4.0.4/node_modules/mime/dist/types/standard.js
848
+ //#region ../../node_modules/.pnpm/mime@4.1.0/node_modules/mime/dist/types/standard.js
825
849
  const types = {
826
850
  "application/andrew-inset": ["ez"],
827
851
  "application/appinstaller": ["appinstaller"],
@@ -852,6 +876,7 @@ const types = {
852
876
  "application/dash+xml": ["mpd"],
853
877
  "application/dash-patch+xml": ["mpp"],
854
878
  "application/davmount+xml": ["davmount"],
879
+ "application/dicom": ["dcm"],
855
880
  "application/docbook+xml": ["dbk"],
856
881
  "application/dssc+der": ["dssc"],
857
882
  "application/dssc+xml": ["xdssc"],
@@ -955,7 +980,9 @@ const types = {
955
980
  "onetoc",
956
981
  "onetoc2",
957
982
  "onetmp",
958
- "onepkg"
983
+ "onepkg",
984
+ "one",
985
+ "onea"
959
986
  ],
960
987
  "application/oxps": ["oxps"],
961
988
  "application/p2p-overlay+xml": ["relo"],
@@ -1066,6 +1093,7 @@ const types = {
1066
1093
  "application/yang": ["yang"],
1067
1094
  "application/yin+xml": ["yin"],
1068
1095
  "application/zip": ["zip"],
1096
+ "application/zip+dotlottie": ["lottie"],
1069
1097
  "audio/3gpp": ["*3gpp"],
1070
1098
  "audio/aac": ["adts", "aac"],
1071
1099
  "audio/adpcm": ["adp"],
@@ -1079,7 +1107,11 @@ const types = {
1079
1107
  ],
1080
1108
  "audio/mobile-xmf": ["mxmf"],
1081
1109
  "audio/mp3": ["*mp3"],
1082
- "audio/mp4": ["m4a", "mp4a"],
1110
+ "audio/mp4": [
1111
+ "m4a",
1112
+ "mp4a",
1113
+ "m4b"
1114
+ ],
1083
1115
  "audio/mpeg": [
1084
1116
  "mpga",
1085
1117
  "mp2",
@@ -1123,19 +1155,21 @@ const types = {
1123
1155
  "image/heif": ["heif"],
1124
1156
  "image/heif-sequence": ["heifs"],
1125
1157
  "image/hej2k": ["hej2"],
1126
- "image/hsj2": ["hsj2"],
1127
1158
  "image/ief": ["ief"],
1159
+ "image/jaii": ["jaii"],
1160
+ "image/jais": ["jais"],
1128
1161
  "image/jls": ["jls"],
1129
1162
  "image/jp2": ["jp2", "jpg2"],
1130
1163
  "image/jpeg": [
1131
- "jpeg",
1132
1164
  "jpg",
1165
+ "jpeg",
1133
1166
  "jpe"
1134
1167
  ],
1135
1168
  "image/jph": ["jph"],
1136
1169
  "image/jphc": ["jhc"],
1137
1170
  "image/jpm": ["jpm", "jpgm"],
1138
1171
  "image/jpx": ["jpx", "jpf"],
1172
+ "image/jxl": ["jxl"],
1139
1173
  "image/jxr": ["jxr"],
1140
1174
  "image/jxra": ["jxra"],
1141
1175
  "image/jxrs": ["jxrs"],
@@ -1145,6 +1179,7 @@ const types = {
1145
1179
  "image/jxss": ["jxss"],
1146
1180
  "image/ktx": ["ktx"],
1147
1181
  "image/ktx2": ["ktx2"],
1182
+ "image/pjpeg": ["jfif"],
1148
1183
  "image/png": ["png"],
1149
1184
  "image/sgi": ["sgi"],
1150
1185
  "image/svg+xml": ["svg", "svgz"],
@@ -1158,7 +1193,12 @@ const types = {
1158
1193
  "message/global-delivery-status": ["u8dsn"],
1159
1194
  "message/global-disposition-notification": ["u8mdn"],
1160
1195
  "message/global-headers": ["u8hdr"],
1161
- "message/rfc822": ["eml", "mime"],
1196
+ "message/rfc822": [
1197
+ "eml",
1198
+ "mime",
1199
+ "mht",
1200
+ "mhtml"
1201
+ ],
1162
1202
  "model/3mf": ["3mf"],
1163
1203
  "model/gltf+json": ["gltf"],
1164
1204
  "model/gltf-binary": ["glb"],
@@ -1172,6 +1212,13 @@ const types = {
1172
1212
  "model/mtl": ["mtl"],
1173
1213
  "model/obj": ["obj"],
1174
1214
  "model/prc": ["prc"],
1215
+ "model/step": [
1216
+ "step",
1217
+ "stp",
1218
+ "stpnc",
1219
+ "p21",
1220
+ "210"
1221
+ ],
1175
1222
  "model/step+xml": ["stpx"],
1176
1223
  "model/step+zip": ["stpz"],
1177
1224
  "model/step-xml+zip": ["stpxz"],
@@ -1247,7 +1294,12 @@ const types = {
1247
1294
  "video/jpeg": ["jpgv"],
1248
1295
  "video/jpm": ["*jpm", "*jpgm"],
1249
1296
  "video/mj2": ["mj2", "mjp2"],
1250
- "video/mp2t": ["ts"],
1297
+ "video/mp2t": [
1298
+ "ts",
1299
+ "m2t",
1300
+ "m2ts",
1301
+ "mts"
1302
+ ],
1251
1303
  "video/mp4": [
1252
1304
  "mp4",
1253
1305
  "mp4v",
@@ -1266,7 +1318,7 @@ const types = {
1266
1318
  };
1267
1319
  Object.freeze(types);
1268
1320
  //#endregion
1269
- //#region ../../node_modules/.pnpm/mime@4.0.4/node_modules/mime/dist/src/Mime.js
1321
+ //#region ../../node_modules/.pnpm/mime@4.1.0/node_modules/mime/dist/src/Mime.js
1270
1322
  var __classPrivateFieldGet = function(receiver, state, kind, f) {
1271
1323
  if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
1272
1324
  if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
@@ -1303,8 +1355,8 @@ var Mime = class {
1303
1355
  }
1304
1356
  getType(path) {
1305
1357
  if (typeof path !== "string") return null;
1306
- const last = path.replace(/^.*[/\\]/, "").toLowerCase();
1307
- const ext = last.replace(/^.*\./, "").toLowerCase();
1358
+ const last = path.replace(/^.*[/\\]/s, "").toLowerCase();
1359
+ const ext = last.replace(/^.*\./s, "").toLowerCase();
1308
1360
  const hasPath = last.length < path.length;
1309
1361
  if (!(ext.length < last.length - 1) && hasPath) return null;
1310
1362
  return __classPrivateFieldGet(this, _Mime_extensionToType, "f").get(ext) ?? null;
@@ -1335,7 +1387,7 @@ var Mime = class {
1335
1387
  };
1336
1388
  _Mime_extensionToType = /* @__PURE__ */ new WeakMap(), _Mime_typeToExtension = /* @__PURE__ */ new WeakMap(), _Mime_typeToExtensions = /* @__PURE__ */ new WeakMap();
1337
1389
  //#endregion
1338
- //#region ../../node_modules/.pnpm/mime@4.0.4/node_modules/mime/dist/src/index.js
1390
+ //#region ../../node_modules/.pnpm/mime@4.1.0/node_modules/mime/dist/src/index.js
1339
1391
  var src_default = new Mime(types, types$1)._freeze();
1340
1392
  //#endregion
1341
1393
  //#region src/runtimeAwsConfig.ts
@@ -1386,6 +1438,8 @@ const streamToString = (stream) => {
1386
1438
  //#region src/s3Database.ts
1387
1439
  const DEFAULT_INVALIDATION_POLL_INTERVAL_MS = 2e3;
1388
1440
  const DEFAULT_INVALIDATION_TIMEOUT_MS = 300 * 1e3;
1441
+ const S3_LIST_OBJECTS_CONCURRENCY = 4;
1442
+ const S3_DIRECTORY_DELIMITER = "/";
1389
1443
  const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
1390
1444
  const getS3ErrorProperty = (error, key) => {
1391
1445
  if (typeof error !== "object" || error === null) return;
@@ -1398,7 +1452,7 @@ const isArchivedS3ObjectError = (error) => {
1398
1452
  };
1399
1453
  const createArchivedS3ObjectError = ({ bucket, key, error }) => {
1400
1454
  const storageClass = getS3ErrorProperty(error, "StorageClass") ?? "archived storage";
1401
- const nextError = new Error(`S3 object "${key}" in bucket "${bucket}" is archived (${storageClass}) and cannot be read. Restore the object in S3 or exclude Hot Updater metadata from lifecycle archival: "_index/**", "**/target-app-versions.json", and "**/update.json".`, { cause: error });
1455
+ const nextError = new Error(`S3 object "${key}" in bucket "${bucket}" is archived (${storageClass}) and cannot be read. Restore the object in S3 or exclude Hot Updater metadata from lifecycle archival: "**/target-app-versions.json" and "**/update.json".`, { cause: error });
1402
1456
  nextError.name = "S3ArchivedObjectError";
1403
1457
  return nextError;
1404
1458
  };
@@ -1418,6 +1472,42 @@ function createDatabaseKeyBuilder(basePath) {
1418
1472
  toStorageKey
1419
1473
  };
1420
1474
  }
1475
+ function normalizeDirectoryPrefix(prefix) {
1476
+ if (!prefix) return "";
1477
+ return prefix.endsWith(S3_DIRECTORY_DELIMITER) ? prefix : `${prefix}${S3_DIRECTORY_DELIMITER}`;
1478
+ }
1479
+ function getRelativeDirectoryPrefix(prefix, rootPrefix) {
1480
+ if (!rootPrefix) return prefix;
1481
+ return prefix.startsWith(rootPrefix) ? prefix.slice(rootPrefix.length) : prefix;
1482
+ }
1483
+ function getDirectoryDepth(prefix, rootPrefix) {
1484
+ return getRelativeDirectoryPrefix(prefix, rootPrefix).split(S3_DIRECTORY_DELIMITER).filter(Boolean).length;
1485
+ }
1486
+ function getLastDirectorySegment(prefix) {
1487
+ return prefix.split(S3_DIRECTORY_DELIMITER).filter(Boolean).at(-1);
1488
+ }
1489
+ function isPlatformDirectoryPrefix(prefix) {
1490
+ const lastSegment = getLastDirectorySegment(prefix);
1491
+ return lastSegment === "ios" || lastSegment === "android";
1492
+ }
1493
+ function isUpdateJsonKey(key) {
1494
+ return key.endsWith(`${S3_DIRECTORY_DELIMITER}update.json`);
1495
+ }
1496
+ async function mapWithConcurrency(items, concurrency, mapper) {
1497
+ const results = [];
1498
+ let nextIndex = 0;
1499
+ const workerCount = Math.min(concurrency, items.length);
1500
+ await Promise.all(Array.from({ length: workerCount }, async () => {
1501
+ while (nextIndex < items.length) {
1502
+ const index = nextIndex;
1503
+ nextIndex += 1;
1504
+ const item = items[index];
1505
+ if (item === void 0) break;
1506
+ results[index] = await mapper(item, index);
1507
+ }
1508
+ }));
1509
+ return results.filter((result) => result !== void 0);
1510
+ }
1421
1511
  /**
1422
1512
  * Loads JSON data from S3.
1423
1513
  * Returns null if NoSuchKey error occurs.
@@ -1445,31 +1535,47 @@ async function loadJsonFromS3(client, bucket, key) {
1445
1535
  * Converts data to JSON string and uploads to S3.
1446
1536
  */
1447
1537
  async function uploadJsonToS3(client, bucket, key, data) {
1448
- await new Upload({
1449
- client,
1450
- params: {
1451
- Bucket: bucket,
1452
- Key: key,
1453
- Body: JSON.stringify(data),
1454
- ContentType: src_default.getType(key) ?? "application/json",
1455
- CacheControl: "max-age=31536000"
1456
- }
1457
- }).done();
1538
+ const Body = JSON.stringify(data);
1539
+ const ContentType = src_default.getType(key) ?? "application/json";
1540
+ await client.send(new PutObjectCommand({
1541
+ Bucket: bucket,
1542
+ Key: key,
1543
+ Body,
1544
+ ContentType,
1545
+ CacheControl: "max-age=31536000"
1546
+ }));
1458
1547
  }
1459
- async function listObjectsInS3(client, bucketName, prefix) {
1460
- let continuationToken;
1461
- const keys = [];
1462
- do {
1463
- const response = await client.send(new ListObjectsV2Command({
1464
- Bucket: bucketName,
1465
- Prefix: prefix,
1466
- ContinuationToken: continuationToken
1467
- }));
1468
- const found = (response.Contents ?? []).map((item) => item.Key).filter((key) => !!key);
1469
- keys.push(...found);
1470
- continuationToken = response.NextContinuationToken;
1471
- } while (continuationToken);
1472
- return keys;
1548
+ async function listObjectsInS3(client, bucketName, prefix, rootPrefix = "") {
1549
+ const normalizedRootPrefix = normalizeDirectoryPrefix(rootPrefix);
1550
+ const listPrefix = async (currentPrefix) => {
1551
+ let continuationToken;
1552
+ const keys = [];
1553
+ const commonPrefixes = /* @__PURE__ */ new Set();
1554
+ do {
1555
+ const response = await client.send(new ListObjectsV2Command({
1556
+ Bucket: bucketName,
1557
+ Prefix: currentPrefix,
1558
+ Delimiter: S3_DIRECTORY_DELIMITER,
1559
+ ContinuationToken: continuationToken
1560
+ }));
1561
+ const found = (response.Contents ?? []).map((item) => item.Key).filter((key) => !!key);
1562
+ keys.push(...found);
1563
+ for (const commonPrefix of response.CommonPrefixes ?? []) if (commonPrefix.Prefix) commonPrefixes.add(commonPrefix.Prefix);
1564
+ continuationToken = response.NextContinuationToken;
1565
+ } while (continuationToken);
1566
+ return {
1567
+ commonPrefixes: Array.from(commonPrefixes),
1568
+ keys
1569
+ };
1570
+ };
1571
+ const collectUpdateJsonKeys = async (currentPrefix) => {
1572
+ const { commonPrefixes, keys } = await listPrefix(currentPrefix);
1573
+ const depth = getDirectoryDepth(currentPrefix, normalizedRootPrefix);
1574
+ if (depth >= 2) return [...keys.filter(isUpdateJsonKey), ...commonPrefixes.map((commonPrefix) => `${commonPrefix}update.json`)];
1575
+ return (await mapWithConcurrency(depth === 1 ? commonPrefixes.filter(isPlatformDirectoryPrefix) : commonPrefixes, S3_LIST_OBJECTS_CONCURRENCY, (nextPrefix) => collectUpdateJsonKeys(nextPrefix))).flat();
1576
+ };
1577
+ const normalizedPrefix = normalizeDirectoryPrefix(prefix);
1578
+ return Array.from(new Set(await collectUpdateJsonKeys(normalizedPrefix)));
1473
1579
  }
1474
1580
  async function deleteObjectInS3(client, bucketName, key) {
1475
1581
  await client.send(new DeleteObjectCommand({
@@ -1524,13 +1630,14 @@ const s3Database = createBlobDatabasePlugin({
1524
1630
  const { basePath, bucketName, cloudfrontDistributionId, apiBasePath = "/api/check-update", shouldWaitForInvalidation = false, ...s3Config } = config;
1525
1631
  const client = new S3Client(applyS3RuntimeAwsConfig(s3Config));
1526
1632
  const { fromStorageKey, toStorageKey } = createDatabaseKeyBuilder(basePath);
1633
+ const rootPrefix = toStorageKey("");
1527
1634
  const cloudfrontClient = cloudfrontDistributionId ? new CloudFrontClient({
1528
1635
  credentials: s3Config.credentials,
1529
1636
  region: s3Config.region
1530
1637
  }) : void 0;
1531
1638
  return {
1532
1639
  apiBasePath,
1533
- listObjects: (prefix) => listObjectsInS3(client, bucketName, toStorageKey(prefix)).then((keys) => keys.map(fromStorageKey)),
1640
+ listObjects: (prefix) => listObjectsInS3(client, bucketName, toStorageKey(prefix), rootPrefix).then((keys) => keys.map(fromStorageKey)),
1534
1641
  loadObject: (key) => loadJsonFromS3(client, bucketName, toStorageKey(key)),
1535
1642
  uploadObject: (key, data) => uploadJsonToS3(client, bucketName, toStorageKey(key), data),
1536
1643
  deleteObject: (key) => deleteObjectInS3(client, bucketName, toStorageKey(key)),