@hot-updater/aws 0.32.0 → 0.33.1
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/iac/index.cjs +181 -15
- package/dist/iac/index.mjs +181 -15
- package/dist/index.cjs +189 -44
- package/dist/index.d.cts +6 -2
- package/dist/index.d.mts +6 -2
- package/dist/index.mjs +190 -45
- package/dist/lambda/index.cjs +1481 -2525
- package/package.json +22 -19
package/dist/index.cjs
CHANGED
|
@@ -23,16 +23,16 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
23
23
|
//#endregion
|
|
24
24
|
let _aws_sdk_client_cloudfront = require("@aws-sdk/client-cloudfront");
|
|
25
25
|
let _aws_sdk_client_s3 = require("@aws-sdk/client-s3");
|
|
26
|
-
let _aws_sdk_lib_storage = require("@aws-sdk/lib-storage");
|
|
27
26
|
let _hot_updater_plugin_core = require("@hot-updater/plugin-core");
|
|
28
27
|
let fs_promises = require("fs/promises");
|
|
29
28
|
fs_promises = __toESM(fs_promises);
|
|
30
29
|
let path = require("path");
|
|
31
30
|
path = __toESM(path);
|
|
31
|
+
let _aws_sdk_lib_storage = require("@aws-sdk/lib-storage");
|
|
32
32
|
let _aws_sdk_s3_request_presigner = require("@aws-sdk/s3-request-presigner");
|
|
33
33
|
let _aws_sdk_client_ssm = require("@aws-sdk/client-ssm");
|
|
34
34
|
let _aws_sdk_cloudfront_signer = require("@aws-sdk/cloudfront-signer");
|
|
35
|
-
//#region ../../node_modules/.pnpm/mime@4.0
|
|
35
|
+
//#region ../../node_modules/.pnpm/mime@4.1.0/node_modules/mime/dist/types/other.js
|
|
36
36
|
const types$1 = {
|
|
37
37
|
"application/prs.cww": ["cww"],
|
|
38
38
|
"application/prs.xsf+xml": ["xsf"],
|
|
@@ -71,6 +71,7 @@ const types$1 = {
|
|
|
71
71
|
"application/vnd.aristanetworks.swi": ["swi"],
|
|
72
72
|
"application/vnd.astraea-software.iota": ["iota"],
|
|
73
73
|
"application/vnd.audiograph": ["aep"],
|
|
74
|
+
"application/vnd.autodesk.fbx": ["fbx"],
|
|
74
75
|
"application/vnd.balsamiq.bmml+xml": ["bmml"],
|
|
75
76
|
"application/vnd.blueice.multipass": ["mpm"],
|
|
76
77
|
"application/vnd.bmi": ["bmi"],
|
|
@@ -106,6 +107,7 @@ const types$1 = {
|
|
|
106
107
|
"application/vnd.dart": ["dart"],
|
|
107
108
|
"application/vnd.data-vision.rdz": ["rdz"],
|
|
108
109
|
"application/vnd.dbf": ["dbf"],
|
|
110
|
+
"application/vnd.dcmp+xml": ["dcmp"],
|
|
109
111
|
"application/vnd.dece.data": [
|
|
110
112
|
"uvf",
|
|
111
113
|
"uvvf",
|
|
@@ -159,6 +161,7 @@ const types$1 = {
|
|
|
159
161
|
"application/vnd.fuzzysheet": ["fzs"],
|
|
160
162
|
"application/vnd.genomatix.tuxedo": ["txd"],
|
|
161
163
|
"application/vnd.geogebra.file": ["ggb"],
|
|
164
|
+
"application/vnd.geogebra.slides": ["ggs"],
|
|
162
165
|
"application/vnd.geogebra.tool": ["ggt"],
|
|
163
166
|
"application/vnd.geometry-explorer": ["gex", "gre"],
|
|
164
167
|
"application/vnd.geonext": ["gxt"],
|
|
@@ -166,10 +169,17 @@ const types$1 = {
|
|
|
166
169
|
"application/vnd.geospace": ["g3w"],
|
|
167
170
|
"application/vnd.gmx": ["gmx"],
|
|
168
171
|
"application/vnd.google-apps.document": ["gdoc"],
|
|
172
|
+
"application/vnd.google-apps.drawing": ["gdraw"],
|
|
173
|
+
"application/vnd.google-apps.form": ["gform"],
|
|
174
|
+
"application/vnd.google-apps.jam": ["gjam"],
|
|
175
|
+
"application/vnd.google-apps.map": ["gmap"],
|
|
169
176
|
"application/vnd.google-apps.presentation": ["gslides"],
|
|
177
|
+
"application/vnd.google-apps.script": ["gscript"],
|
|
178
|
+
"application/vnd.google-apps.site": ["gsite"],
|
|
170
179
|
"application/vnd.google-apps.spreadsheet": ["gsheet"],
|
|
171
180
|
"application/vnd.google-earth.kml+xml": ["kml"],
|
|
172
181
|
"application/vnd.google-earth.kmz": ["kmz"],
|
|
182
|
+
"application/vnd.gov.sk.xmldatacontainer+xml": ["xdcf"],
|
|
173
183
|
"application/vnd.grafeq": ["gqf", "gqs"],
|
|
174
184
|
"application/vnd.groove-account": ["gac"],
|
|
175
185
|
"application/vnd.groove-help": ["ghf"],
|
|
@@ -296,6 +306,7 @@ const types$1 = {
|
|
|
296
306
|
"application/vnd.ms-powerpoint.slideshow.macroenabled.12": ["ppsm"],
|
|
297
307
|
"application/vnd.ms-powerpoint.template.macroenabled.12": ["potm"],
|
|
298
308
|
"application/vnd.ms-project": ["*mpp", "mpt"],
|
|
309
|
+
"application/vnd.ms-visio.viewer": ["vdx"],
|
|
299
310
|
"application/vnd.ms-word.document.macroenabled.12": ["docm"],
|
|
300
311
|
"application/vnd.ms-word.template.macroenabled.12": ["dotm"],
|
|
301
312
|
"application/vnd.ms-works": [
|
|
@@ -310,6 +321,7 @@ const types$1 = {
|
|
|
310
321
|
"application/vnd.musician": ["mus"],
|
|
311
322
|
"application/vnd.muvee.style": ["msty"],
|
|
312
323
|
"application/vnd.mynfc": ["taglet"],
|
|
324
|
+
"application/vnd.nato.bindingdataobject+xml": ["bdo"],
|
|
313
325
|
"application/vnd.neurolanguage.nlu": ["nlu"],
|
|
314
326
|
"application/vnd.nitf": ["ntf", "nitf"],
|
|
315
327
|
"application/vnd.noblenet-directory": ["nnd"],
|
|
@@ -369,6 +381,9 @@ const types$1 = {
|
|
|
369
381
|
"application/vnd.pocketlearn": ["plf"],
|
|
370
382
|
"application/vnd.powerbuilder6": ["pbd"],
|
|
371
383
|
"application/vnd.previewsystems.box": ["box"],
|
|
384
|
+
"application/vnd.procrate.brushset": ["brushset"],
|
|
385
|
+
"application/vnd.procreate.brush": ["brush"],
|
|
386
|
+
"application/vnd.procreate.dream": ["drm"],
|
|
372
387
|
"application/vnd.proteus.magazine": ["mgz"],
|
|
373
388
|
"application/vnd.publishare-delta-tree": ["qps"],
|
|
374
389
|
"application/vnd.pvi.ptid1": ["ptid"],
|
|
@@ -452,7 +467,9 @@ const types$1 = {
|
|
|
452
467
|
"vsd",
|
|
453
468
|
"vst",
|
|
454
469
|
"vss",
|
|
455
|
-
"vsw"
|
|
470
|
+
"vsw",
|
|
471
|
+
"vsdx",
|
|
472
|
+
"vtx"
|
|
456
473
|
],
|
|
457
474
|
"application/vnd.visionary": ["vis"],
|
|
458
475
|
"application/vnd.vsf": ["vsf"],
|
|
@@ -492,6 +509,7 @@ const types$1 = {
|
|
|
492
509
|
"application/x-bcpio": ["bcpio"],
|
|
493
510
|
"application/x-bdoc": ["*bdoc"],
|
|
494
511
|
"application/x-bittorrent": ["torrent"],
|
|
512
|
+
"application/x-blender": ["blend"],
|
|
495
513
|
"application/x-blorb": ["blb", "blorb"],
|
|
496
514
|
"application/x-bzip": ["bz"],
|
|
497
515
|
"application/x-bzip2": ["bz2", "boz"],
|
|
@@ -508,6 +526,7 @@ const types$1 = {
|
|
|
508
526
|
"application/x-chess-pgn": ["pgn"],
|
|
509
527
|
"application/x-chrome-extension": ["crx"],
|
|
510
528
|
"application/x-cocoa": ["cco"],
|
|
529
|
+
"application/x-compressed": ["*rar"],
|
|
511
530
|
"application/x-conference": ["nsc"],
|
|
512
531
|
"application/x-cpio": ["cpio"],
|
|
513
532
|
"application/x-csh": ["csh"],
|
|
@@ -552,6 +571,7 @@ const types$1 = {
|
|
|
552
571
|
"application/x-hdf": ["hdf"],
|
|
553
572
|
"application/x-httpd-php": ["php"],
|
|
554
573
|
"application/x-install-instructions": ["install"],
|
|
574
|
+
"application/x-ipynb+json": ["ipynb"],
|
|
555
575
|
"application/x-iso9660-image": ["*iso"],
|
|
556
576
|
"application/x-iwork-keynote-sffkey": ["*key"],
|
|
557
577
|
"application/x-iwork-numbers-sffnumbers": ["*numbers"],
|
|
@@ -648,6 +668,7 @@ const types$1 = {
|
|
|
648
668
|
"application/x-xliff+xml": ["*xlf"],
|
|
649
669
|
"application/x-xpinstall": ["xpi"],
|
|
650
670
|
"application/x-xz": ["xz"],
|
|
671
|
+
"application/x-zip-compressed": ["*zip"],
|
|
651
672
|
"application/x-zmachine": [
|
|
652
673
|
"z1",
|
|
653
674
|
"z2",
|
|
@@ -696,6 +717,7 @@ const types$1 = {
|
|
|
696
717
|
"image/prs.pti": ["pti"],
|
|
697
718
|
"image/vnd.adobe.photoshop": ["psd"],
|
|
698
719
|
"image/vnd.airzip.accelerator.azv": ["azv"],
|
|
720
|
+
"image/vnd.blockfact.facti": ["facti"],
|
|
699
721
|
"image/vnd.dece.graphic": [
|
|
700
722
|
"uvi",
|
|
701
723
|
"uvvi",
|
|
@@ -723,6 +745,7 @@ const types$1 = {
|
|
|
723
745
|
"image/vnd.xiff": ["xif"],
|
|
724
746
|
"image/vnd.zbrush.pcx": ["pcx"],
|
|
725
747
|
"image/x-3ds": ["3ds"],
|
|
748
|
+
"image/x-adobe-dng": ["dng"],
|
|
726
749
|
"image/x-cmu-raster": ["ras"],
|
|
727
750
|
"image/x-cmx": ["cmx"],
|
|
728
751
|
"image/x-freehand": [
|
|
@@ -748,12 +771,13 @@ const types$1 = {
|
|
|
748
771
|
"image/x-xpixmap": ["xpm"],
|
|
749
772
|
"image/x-xwindowdump": ["xwd"],
|
|
750
773
|
"message/vnd.wfa.wsc": ["wsc"],
|
|
774
|
+
"model/vnd.bary": ["bary"],
|
|
751
775
|
"model/vnd.cld": ["cld"],
|
|
752
776
|
"model/vnd.collada+xml": ["dae"],
|
|
753
777
|
"model/vnd.dwf": ["dwf"],
|
|
754
778
|
"model/vnd.gdl": ["gdl"],
|
|
755
779
|
"model/vnd.gtw": ["gtw"],
|
|
756
|
-
"model/vnd.mts": ["mts"],
|
|
780
|
+
"model/vnd.mts": ["*mts"],
|
|
757
781
|
"model/vnd.opengex": ["ogex"],
|
|
758
782
|
"model/vnd.parasolid.transmit.binary": ["x_b"],
|
|
759
783
|
"model/vnd.parasolid.transmit.text": ["x_t"],
|
|
@@ -846,7 +870,7 @@ const types$1 = {
|
|
|
846
870
|
};
|
|
847
871
|
Object.freeze(types$1);
|
|
848
872
|
//#endregion
|
|
849
|
-
//#region ../../node_modules/.pnpm/mime@4.0
|
|
873
|
+
//#region ../../node_modules/.pnpm/mime@4.1.0/node_modules/mime/dist/types/standard.js
|
|
850
874
|
const types = {
|
|
851
875
|
"application/andrew-inset": ["ez"],
|
|
852
876
|
"application/appinstaller": ["appinstaller"],
|
|
@@ -877,6 +901,7 @@ const types = {
|
|
|
877
901
|
"application/dash+xml": ["mpd"],
|
|
878
902
|
"application/dash-patch+xml": ["mpp"],
|
|
879
903
|
"application/davmount+xml": ["davmount"],
|
|
904
|
+
"application/dicom": ["dcm"],
|
|
880
905
|
"application/docbook+xml": ["dbk"],
|
|
881
906
|
"application/dssc+der": ["dssc"],
|
|
882
907
|
"application/dssc+xml": ["xdssc"],
|
|
@@ -980,7 +1005,9 @@ const types = {
|
|
|
980
1005
|
"onetoc",
|
|
981
1006
|
"onetoc2",
|
|
982
1007
|
"onetmp",
|
|
983
|
-
"onepkg"
|
|
1008
|
+
"onepkg",
|
|
1009
|
+
"one",
|
|
1010
|
+
"onea"
|
|
984
1011
|
],
|
|
985
1012
|
"application/oxps": ["oxps"],
|
|
986
1013
|
"application/p2p-overlay+xml": ["relo"],
|
|
@@ -1091,6 +1118,7 @@ const types = {
|
|
|
1091
1118
|
"application/yang": ["yang"],
|
|
1092
1119
|
"application/yin+xml": ["yin"],
|
|
1093
1120
|
"application/zip": ["zip"],
|
|
1121
|
+
"application/zip+dotlottie": ["lottie"],
|
|
1094
1122
|
"audio/3gpp": ["*3gpp"],
|
|
1095
1123
|
"audio/aac": ["adts", "aac"],
|
|
1096
1124
|
"audio/adpcm": ["adp"],
|
|
@@ -1104,7 +1132,11 @@ const types = {
|
|
|
1104
1132
|
],
|
|
1105
1133
|
"audio/mobile-xmf": ["mxmf"],
|
|
1106
1134
|
"audio/mp3": ["*mp3"],
|
|
1107
|
-
"audio/mp4": [
|
|
1135
|
+
"audio/mp4": [
|
|
1136
|
+
"m4a",
|
|
1137
|
+
"mp4a",
|
|
1138
|
+
"m4b"
|
|
1139
|
+
],
|
|
1108
1140
|
"audio/mpeg": [
|
|
1109
1141
|
"mpga",
|
|
1110
1142
|
"mp2",
|
|
@@ -1148,19 +1180,21 @@ const types = {
|
|
|
1148
1180
|
"image/heif": ["heif"],
|
|
1149
1181
|
"image/heif-sequence": ["heifs"],
|
|
1150
1182
|
"image/hej2k": ["hej2"],
|
|
1151
|
-
"image/hsj2": ["hsj2"],
|
|
1152
1183
|
"image/ief": ["ief"],
|
|
1184
|
+
"image/jaii": ["jaii"],
|
|
1185
|
+
"image/jais": ["jais"],
|
|
1153
1186
|
"image/jls": ["jls"],
|
|
1154
1187
|
"image/jp2": ["jp2", "jpg2"],
|
|
1155
1188
|
"image/jpeg": [
|
|
1156
|
-
"jpeg",
|
|
1157
1189
|
"jpg",
|
|
1190
|
+
"jpeg",
|
|
1158
1191
|
"jpe"
|
|
1159
1192
|
],
|
|
1160
1193
|
"image/jph": ["jph"],
|
|
1161
1194
|
"image/jphc": ["jhc"],
|
|
1162
1195
|
"image/jpm": ["jpm", "jpgm"],
|
|
1163
1196
|
"image/jpx": ["jpx", "jpf"],
|
|
1197
|
+
"image/jxl": ["jxl"],
|
|
1164
1198
|
"image/jxr": ["jxr"],
|
|
1165
1199
|
"image/jxra": ["jxra"],
|
|
1166
1200
|
"image/jxrs": ["jxrs"],
|
|
@@ -1170,6 +1204,7 @@ const types = {
|
|
|
1170
1204
|
"image/jxss": ["jxss"],
|
|
1171
1205
|
"image/ktx": ["ktx"],
|
|
1172
1206
|
"image/ktx2": ["ktx2"],
|
|
1207
|
+
"image/pjpeg": ["jfif"],
|
|
1173
1208
|
"image/png": ["png"],
|
|
1174
1209
|
"image/sgi": ["sgi"],
|
|
1175
1210
|
"image/svg+xml": ["svg", "svgz"],
|
|
@@ -1183,7 +1218,12 @@ const types = {
|
|
|
1183
1218
|
"message/global-delivery-status": ["u8dsn"],
|
|
1184
1219
|
"message/global-disposition-notification": ["u8mdn"],
|
|
1185
1220
|
"message/global-headers": ["u8hdr"],
|
|
1186
|
-
"message/rfc822": [
|
|
1221
|
+
"message/rfc822": [
|
|
1222
|
+
"eml",
|
|
1223
|
+
"mime",
|
|
1224
|
+
"mht",
|
|
1225
|
+
"mhtml"
|
|
1226
|
+
],
|
|
1187
1227
|
"model/3mf": ["3mf"],
|
|
1188
1228
|
"model/gltf+json": ["gltf"],
|
|
1189
1229
|
"model/gltf-binary": ["glb"],
|
|
@@ -1197,6 +1237,13 @@ const types = {
|
|
|
1197
1237
|
"model/mtl": ["mtl"],
|
|
1198
1238
|
"model/obj": ["obj"],
|
|
1199
1239
|
"model/prc": ["prc"],
|
|
1240
|
+
"model/step": [
|
|
1241
|
+
"step",
|
|
1242
|
+
"stp",
|
|
1243
|
+
"stpnc",
|
|
1244
|
+
"p21",
|
|
1245
|
+
"210"
|
|
1246
|
+
],
|
|
1200
1247
|
"model/step+xml": ["stpx"],
|
|
1201
1248
|
"model/step+zip": ["stpz"],
|
|
1202
1249
|
"model/step-xml+zip": ["stpxz"],
|
|
@@ -1272,7 +1319,12 @@ const types = {
|
|
|
1272
1319
|
"video/jpeg": ["jpgv"],
|
|
1273
1320
|
"video/jpm": ["*jpm", "*jpgm"],
|
|
1274
1321
|
"video/mj2": ["mj2", "mjp2"],
|
|
1275
|
-
"video/mp2t": [
|
|
1322
|
+
"video/mp2t": [
|
|
1323
|
+
"ts",
|
|
1324
|
+
"m2t",
|
|
1325
|
+
"m2ts",
|
|
1326
|
+
"mts"
|
|
1327
|
+
],
|
|
1276
1328
|
"video/mp4": [
|
|
1277
1329
|
"mp4",
|
|
1278
1330
|
"mp4v",
|
|
@@ -1291,7 +1343,7 @@ const types = {
|
|
|
1291
1343
|
};
|
|
1292
1344
|
Object.freeze(types);
|
|
1293
1345
|
//#endregion
|
|
1294
|
-
//#region ../../node_modules/.pnpm/mime@4.0
|
|
1346
|
+
//#region ../../node_modules/.pnpm/mime@4.1.0/node_modules/mime/dist/src/Mime.js
|
|
1295
1347
|
var __classPrivateFieldGet = function(receiver, state, kind, f) {
|
|
1296
1348
|
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
|
|
1297
1349
|
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");
|
|
@@ -1328,8 +1380,8 @@ var Mime = class {
|
|
|
1328
1380
|
}
|
|
1329
1381
|
getType(path) {
|
|
1330
1382
|
if (typeof path !== "string") return null;
|
|
1331
|
-
const last = path.replace(/^.*[/\\]
|
|
1332
|
-
const ext = last.replace(
|
|
1383
|
+
const last = path.replace(/^.*[/\\]/s, "").toLowerCase();
|
|
1384
|
+
const ext = last.replace(/^.*\./s, "").toLowerCase();
|
|
1333
1385
|
const hasPath = last.length < path.length;
|
|
1334
1386
|
if (!(ext.length < last.length - 1) && hasPath) return null;
|
|
1335
1387
|
return __classPrivateFieldGet(this, _Mime_extensionToType, "f").get(ext) ?? null;
|
|
@@ -1360,7 +1412,7 @@ var Mime = class {
|
|
|
1360
1412
|
};
|
|
1361
1413
|
_Mime_extensionToType = /* @__PURE__ */ new WeakMap(), _Mime_typeToExtension = /* @__PURE__ */ new WeakMap(), _Mime_typeToExtensions = /* @__PURE__ */ new WeakMap();
|
|
1362
1414
|
//#endregion
|
|
1363
|
-
//#region ../../node_modules/.pnpm/mime@4.0
|
|
1415
|
+
//#region ../../node_modules/.pnpm/mime@4.1.0/node_modules/mime/dist/src/index.js
|
|
1364
1416
|
var src_default = new Mime(types, types$1)._freeze();
|
|
1365
1417
|
//#endregion
|
|
1366
1418
|
//#region src/runtimeAwsConfig.ts
|
|
@@ -1411,7 +1463,76 @@ const streamToString = (stream) => {
|
|
|
1411
1463
|
//#region src/s3Database.ts
|
|
1412
1464
|
const DEFAULT_INVALIDATION_POLL_INTERVAL_MS = 2e3;
|
|
1413
1465
|
const DEFAULT_INVALIDATION_TIMEOUT_MS = 300 * 1e3;
|
|
1466
|
+
const S3_LIST_OBJECTS_CONCURRENCY = 4;
|
|
1467
|
+
const S3_DIRECTORY_DELIMITER = "/";
|
|
1414
1468
|
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
1469
|
+
const getS3ErrorProperty = (error, key) => {
|
|
1470
|
+
if (typeof error !== "object" || error === null) return;
|
|
1471
|
+
const value = error[key];
|
|
1472
|
+
return typeof value === "string" ? value : void 0;
|
|
1473
|
+
};
|
|
1474
|
+
const isArchivedS3ObjectError = (error) => {
|
|
1475
|
+
if (!(error instanceof Error)) return false;
|
|
1476
|
+
return error.name === "InvalidObjectState" || getS3ErrorProperty(error, "Code") === "InvalidObjectState";
|
|
1477
|
+
};
|
|
1478
|
+
const createArchivedS3ObjectError = ({ bucket, key, error }) => {
|
|
1479
|
+
const storageClass = getS3ErrorProperty(error, "StorageClass") ?? "archived storage";
|
|
1480
|
+
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 });
|
|
1481
|
+
nextError.name = "S3ArchivedObjectError";
|
|
1482
|
+
return nextError;
|
|
1483
|
+
};
|
|
1484
|
+
function normalizeBasePath(basePath) {
|
|
1485
|
+
return basePath?.replace(/^\/+|\/+$/g, "") ?? "";
|
|
1486
|
+
}
|
|
1487
|
+
function createDatabaseKeyBuilder(basePath) {
|
|
1488
|
+
const normalizedBasePath = normalizeBasePath(basePath);
|
|
1489
|
+
const toStorageKey = (key) => [normalizedBasePath, key].filter(Boolean).join("/");
|
|
1490
|
+
const fromStorageKey = (key) => {
|
|
1491
|
+
if (!normalizedBasePath) return key;
|
|
1492
|
+
const prefix = `${normalizedBasePath}/`;
|
|
1493
|
+
return key.startsWith(prefix) ? key.slice(prefix.length) : key;
|
|
1494
|
+
};
|
|
1495
|
+
return {
|
|
1496
|
+
fromStorageKey,
|
|
1497
|
+
toStorageKey
|
|
1498
|
+
};
|
|
1499
|
+
}
|
|
1500
|
+
function normalizeDirectoryPrefix(prefix) {
|
|
1501
|
+
if (!prefix) return "";
|
|
1502
|
+
return prefix.endsWith(S3_DIRECTORY_DELIMITER) ? prefix : `${prefix}${S3_DIRECTORY_DELIMITER}`;
|
|
1503
|
+
}
|
|
1504
|
+
function getRelativeDirectoryPrefix(prefix, rootPrefix) {
|
|
1505
|
+
if (!rootPrefix) return prefix;
|
|
1506
|
+
return prefix.startsWith(rootPrefix) ? prefix.slice(rootPrefix.length) : prefix;
|
|
1507
|
+
}
|
|
1508
|
+
function getDirectoryDepth(prefix, rootPrefix) {
|
|
1509
|
+
return getRelativeDirectoryPrefix(prefix, rootPrefix).split(S3_DIRECTORY_DELIMITER).filter(Boolean).length;
|
|
1510
|
+
}
|
|
1511
|
+
function getLastDirectorySegment(prefix) {
|
|
1512
|
+
return prefix.split(S3_DIRECTORY_DELIMITER).filter(Boolean).at(-1);
|
|
1513
|
+
}
|
|
1514
|
+
function isPlatformDirectoryPrefix(prefix) {
|
|
1515
|
+
const lastSegment = getLastDirectorySegment(prefix);
|
|
1516
|
+
return lastSegment === "ios" || lastSegment === "android";
|
|
1517
|
+
}
|
|
1518
|
+
function isUpdateJsonKey(key) {
|
|
1519
|
+
return key.endsWith(`${S3_DIRECTORY_DELIMITER}update.json`);
|
|
1520
|
+
}
|
|
1521
|
+
async function mapWithConcurrency(items, concurrency, mapper) {
|
|
1522
|
+
const results = [];
|
|
1523
|
+
let nextIndex = 0;
|
|
1524
|
+
const workerCount = Math.min(concurrency, items.length);
|
|
1525
|
+
await Promise.all(Array.from({ length: workerCount }, async () => {
|
|
1526
|
+
while (nextIndex < items.length) {
|
|
1527
|
+
const index = nextIndex;
|
|
1528
|
+
nextIndex += 1;
|
|
1529
|
+
const item = items[index];
|
|
1530
|
+
if (item === void 0) break;
|
|
1531
|
+
results[index] = await mapper(item, index);
|
|
1532
|
+
}
|
|
1533
|
+
}));
|
|
1534
|
+
return results.filter((result) => result !== void 0);
|
|
1535
|
+
}
|
|
1415
1536
|
/**
|
|
1416
1537
|
* Loads JSON data from S3.
|
|
1417
1538
|
* Returns null if NoSuchKey error occurs.
|
|
@@ -1427,6 +1548,11 @@ async function loadJsonFromS3(client, bucket, key) {
|
|
|
1427
1548
|
return JSON.parse(bodyContents);
|
|
1428
1549
|
} catch (e) {
|
|
1429
1550
|
if (e instanceof _aws_sdk_client_s3.NoSuchKey) return null;
|
|
1551
|
+
if (isArchivedS3ObjectError(e)) throw createArchivedS3ObjectError({
|
|
1552
|
+
bucket,
|
|
1553
|
+
key,
|
|
1554
|
+
error: e
|
|
1555
|
+
});
|
|
1430
1556
|
throw e;
|
|
1431
1557
|
}
|
|
1432
1558
|
}
|
|
@@ -1434,31 +1560,47 @@ async function loadJsonFromS3(client, bucket, key) {
|
|
|
1434
1560
|
* Converts data to JSON string and uploads to S3.
|
|
1435
1561
|
*/
|
|
1436
1562
|
async function uploadJsonToS3(client, bucket, key, data) {
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
}).done();
|
|
1563
|
+
const Body = JSON.stringify(data);
|
|
1564
|
+
const ContentType = src_default.getType(key) ?? "application/json";
|
|
1565
|
+
await client.send(new _aws_sdk_client_s3.PutObjectCommand({
|
|
1566
|
+
Bucket: bucket,
|
|
1567
|
+
Key: key,
|
|
1568
|
+
Body,
|
|
1569
|
+
ContentType,
|
|
1570
|
+
CacheControl: "max-age=31536000"
|
|
1571
|
+
}));
|
|
1447
1572
|
}
|
|
1448
|
-
async function listObjectsInS3(client, bucketName, prefix) {
|
|
1449
|
-
|
|
1450
|
-
const
|
|
1451
|
-
|
|
1452
|
-
const
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1573
|
+
async function listObjectsInS3(client, bucketName, prefix, rootPrefix = "") {
|
|
1574
|
+
const normalizedRootPrefix = normalizeDirectoryPrefix(rootPrefix);
|
|
1575
|
+
const listPrefix = async (currentPrefix) => {
|
|
1576
|
+
let continuationToken;
|
|
1577
|
+
const keys = [];
|
|
1578
|
+
const commonPrefixes = /* @__PURE__ */ new Set();
|
|
1579
|
+
do {
|
|
1580
|
+
const response = await client.send(new _aws_sdk_client_s3.ListObjectsV2Command({
|
|
1581
|
+
Bucket: bucketName,
|
|
1582
|
+
Prefix: currentPrefix,
|
|
1583
|
+
Delimiter: S3_DIRECTORY_DELIMITER,
|
|
1584
|
+
ContinuationToken: continuationToken
|
|
1585
|
+
}));
|
|
1586
|
+
const found = (response.Contents ?? []).map((item) => item.Key).filter((key) => !!key);
|
|
1587
|
+
keys.push(...found);
|
|
1588
|
+
for (const commonPrefix of response.CommonPrefixes ?? []) if (commonPrefix.Prefix) commonPrefixes.add(commonPrefix.Prefix);
|
|
1589
|
+
continuationToken = response.NextContinuationToken;
|
|
1590
|
+
} while (continuationToken);
|
|
1591
|
+
return {
|
|
1592
|
+
commonPrefixes: Array.from(commonPrefixes),
|
|
1593
|
+
keys
|
|
1594
|
+
};
|
|
1595
|
+
};
|
|
1596
|
+
const collectUpdateJsonKeys = async (currentPrefix) => {
|
|
1597
|
+
const { commonPrefixes, keys } = await listPrefix(currentPrefix);
|
|
1598
|
+
const depth = getDirectoryDepth(currentPrefix, normalizedRootPrefix);
|
|
1599
|
+
if (depth >= 2) return [...keys.filter(isUpdateJsonKey), ...commonPrefixes.map((commonPrefix) => `${commonPrefix}update.json`)];
|
|
1600
|
+
return (await mapWithConcurrency(depth === 1 ? commonPrefixes.filter(isPlatformDirectoryPrefix) : commonPrefixes, S3_LIST_OBJECTS_CONCURRENCY, (nextPrefix) => collectUpdateJsonKeys(nextPrefix))).flat();
|
|
1601
|
+
};
|
|
1602
|
+
const normalizedPrefix = normalizeDirectoryPrefix(prefix);
|
|
1603
|
+
return Array.from(new Set(await collectUpdateJsonKeys(normalizedPrefix)));
|
|
1462
1604
|
}
|
|
1463
1605
|
async function deleteObjectInS3(client, bucketName, key) {
|
|
1464
1606
|
await client.send(new _aws_sdk_client_s3.DeleteObjectCommand({
|
|
@@ -1510,18 +1652,21 @@ async function invalidateCloudFront(client, distributionId, paths, options) {
|
|
|
1510
1652
|
const s3Database = (0, _hot_updater_plugin_core.createBlobDatabasePlugin)({
|
|
1511
1653
|
name: "s3Database",
|
|
1512
1654
|
factory: (config) => {
|
|
1513
|
-
const { bucketName, cloudfrontDistributionId, apiBasePath = "/api/check-update", shouldWaitForInvalidation = false, ...s3Config } = config;
|
|
1655
|
+
const { basePath, bucketName, cloudfrontDistributionId, apiBasePath = "/api/check-update", shouldWaitForInvalidation = false, ...s3Config } = config;
|
|
1514
1656
|
const client = new _aws_sdk_client_s3.S3Client(applyS3RuntimeAwsConfig(s3Config));
|
|
1657
|
+
const { fromStorageKey, toStorageKey } = createDatabaseKeyBuilder(basePath);
|
|
1658
|
+
const rootPrefix = toStorageKey("");
|
|
1515
1659
|
const cloudfrontClient = cloudfrontDistributionId ? new _aws_sdk_client_cloudfront.CloudFrontClient({
|
|
1516
1660
|
credentials: s3Config.credentials,
|
|
1517
1661
|
region: s3Config.region
|
|
1518
1662
|
}) : void 0;
|
|
1519
1663
|
return {
|
|
1520
1664
|
apiBasePath,
|
|
1521
|
-
listObjects: (prefix) => listObjectsInS3(client, bucketName, prefix),
|
|
1522
|
-
loadObject: (key) => loadJsonFromS3(client, bucketName, key),
|
|
1523
|
-
uploadObject: (key, data) => uploadJsonToS3(client, bucketName, key, data),
|
|
1524
|
-
deleteObject: (key) => deleteObjectInS3(client, bucketName, key),
|
|
1665
|
+
listObjects: (prefix) => listObjectsInS3(client, bucketName, toStorageKey(prefix), rootPrefix).then((keys) => keys.map(fromStorageKey)),
|
|
1666
|
+
loadObject: (key) => loadJsonFromS3(client, bucketName, toStorageKey(key)),
|
|
1667
|
+
uploadObject: (key, data) => uploadJsonToS3(client, bucketName, toStorageKey(key), data),
|
|
1668
|
+
deleteObject: (key) => deleteObjectInS3(client, bucketName, toStorageKey(key)),
|
|
1669
|
+
shouldSkipLoadObjectError: (error) => error instanceof Error && error.name === "S3ArchivedObjectError",
|
|
1525
1670
|
invalidatePaths: (pathsToInvalidate) => {
|
|
1526
1671
|
if (cloudfrontClient && cloudfrontDistributionId && pathsToInvalidate.length > 0) return invalidateCloudFront(cloudfrontClient, cloudfrontDistributionId, pathsToInvalidate, { shouldWaitForInvalidation });
|
|
1527
1672
|
return Promise.resolve();
|
package/dist/index.d.cts
CHANGED
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
import * as _$_hot_updater_plugin_core0 from "@hot-updater/plugin-core";
|
|
2
|
-
import {
|
|
2
|
+
import { RuntimeStoragePlugin, StoragePluginHooks, StorageResolveContext } from "@hot-updater/plugin-core";
|
|
3
3
|
import { S3ClientConfig } from "@aws-sdk/client-s3";
|
|
4
4
|
|
|
5
5
|
//#region src/s3Database.d.ts
|
|
6
|
-
interface S3DatabaseConfig extends S3ClientConfig
|
|
6
|
+
interface S3DatabaseConfig extends S3ClientConfig {
|
|
7
7
|
bucketName: string;
|
|
8
|
+
/**
|
|
9
|
+
* Base path where database objects will be stored in the bucket.
|
|
10
|
+
*/
|
|
11
|
+
basePath?: string;
|
|
8
12
|
/**
|
|
9
13
|
* CloudFront distribution ID used for cache invalidation.
|
|
10
14
|
*
|
package/dist/index.d.mts
CHANGED
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
import { S3ClientConfig } from "@aws-sdk/client-s3";
|
|
2
2
|
import * as _$_hot_updater_plugin_core0 from "@hot-updater/plugin-core";
|
|
3
|
-
import {
|
|
3
|
+
import { RuntimeStoragePlugin, StoragePluginHooks, StorageResolveContext } from "@hot-updater/plugin-core";
|
|
4
4
|
|
|
5
5
|
//#region src/s3Database.d.ts
|
|
6
|
-
interface S3DatabaseConfig extends S3ClientConfig
|
|
6
|
+
interface S3DatabaseConfig extends S3ClientConfig {
|
|
7
7
|
bucketName: string;
|
|
8
|
+
/**
|
|
9
|
+
* Base path where database objects will be stored in the bucket.
|
|
10
|
+
*/
|
|
11
|
+
basePath?: string;
|
|
8
12
|
/**
|
|
9
13
|
* CloudFront distribution ID used for cache invalidation.
|
|
10
14
|
*
|