@hot-updater/aws 0.36.7 → 1.0.0-rc.0

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
@@ -1,1419 +1,1786 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- //#region \0rolldown/runtime.js
3
- var __create = Object.create;
4
- var __defProp = Object.defineProperty;
5
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
6
- var __getOwnPropNames = Object.getOwnPropertyNames;
7
- var __getProtoOf = Object.getPrototypeOf;
8
- var __hasOwnProp = Object.prototype.hasOwnProperty;
9
- var __copyProps = (to, from, except, desc) => {
10
- if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
11
- key = keys[i];
12
- if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
13
- get: ((k) => from[k]).bind(null, key),
14
- enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
15
- });
16
- }
17
- return to;
18
- };
19
- var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
20
- value: mod,
21
- enumerable: true
22
- }) : target, mod));
23
- //#endregion
24
2
  let _aws_sdk_client_cloudfront = require("@aws-sdk/client-cloudfront");
25
- let _aws_sdk_client_s3 = require("@aws-sdk/client-s3");
3
+ let _aws_sdk_client_dynamodb = require("@aws-sdk/client-dynamodb");
4
+ let _aws_sdk_lib_dynamodb = require("@aws-sdk/lib-dynamodb");
26
5
  let _hot_updater_plugin_core = require("@hot-updater/plugin-core");
27
- let fs_promises = require("fs/promises");
28
- fs_promises = __toESM(fs_promises);
29
- let path = require("path");
30
- path = __toESM(path);
31
- let _aws_sdk_lib_storage = require("@aws-sdk/lib-storage");
32
- let _aws_sdk_s3_request_presigner = require("@aws-sdk/s3-request-presigner");
6
+ let _hot_updater_plugin_core_internal = require("@hot-updater/plugin-core/internal");
33
7
  let _aws_sdk_client_ssm = require("@aws-sdk/client-ssm");
34
8
  let _aws_sdk_cloudfront_signer = require("@aws-sdk/cloudfront-signer");
35
- //#region ../../node_modules/.pnpm/mime@4.1.0/node_modules/mime/dist/types/other.js
36
- const types$1 = {
37
- "application/prs.cww": ["cww"],
38
- "application/prs.xsf+xml": ["xsf"],
39
- "application/vnd.1000minds.decision-model+xml": ["1km"],
40
- "application/vnd.3gpp.pic-bw-large": ["plb"],
41
- "application/vnd.3gpp.pic-bw-small": ["psb"],
42
- "application/vnd.3gpp.pic-bw-var": ["pvb"],
43
- "application/vnd.3gpp2.tcap": ["tcap"],
44
- "application/vnd.3m.post-it-notes": ["pwn"],
45
- "application/vnd.accpac.simply.aso": ["aso"],
46
- "application/vnd.accpac.simply.imp": ["imp"],
47
- "application/vnd.acucobol": ["acu"],
48
- "application/vnd.acucorp": ["atc", "acutc"],
49
- "application/vnd.adobe.air-application-installer-package+zip": ["air"],
50
- "application/vnd.adobe.formscentral.fcdt": ["fcdt"],
51
- "application/vnd.adobe.fxp": ["fxp", "fxpl"],
52
- "application/vnd.adobe.xdp+xml": ["xdp"],
53
- "application/vnd.adobe.xfdf": ["*xfdf"],
54
- "application/vnd.age": ["age"],
55
- "application/vnd.ahead.space": ["ahead"],
56
- "application/vnd.airzip.filesecure.azf": ["azf"],
57
- "application/vnd.airzip.filesecure.azs": ["azs"],
58
- "application/vnd.amazon.ebook": ["azw"],
59
- "application/vnd.americandynamics.acc": ["acc"],
60
- "application/vnd.amiga.ami": ["ami"],
61
- "application/vnd.android.package-archive": ["apk"],
62
- "application/vnd.anser-web-certificate-issue-initiation": ["cii"],
63
- "application/vnd.anser-web-funds-transfer-initiation": ["fti"],
64
- "application/vnd.antix.game-component": ["atx"],
65
- "application/vnd.apple.installer+xml": ["mpkg"],
66
- "application/vnd.apple.keynote": ["key"],
67
- "application/vnd.apple.mpegurl": ["m3u8"],
68
- "application/vnd.apple.numbers": ["numbers"],
69
- "application/vnd.apple.pages": ["pages"],
70
- "application/vnd.apple.pkpass": ["pkpass"],
71
- "application/vnd.aristanetworks.swi": ["swi"],
72
- "application/vnd.astraea-software.iota": ["iota"],
73
- "application/vnd.audiograph": ["aep"],
74
- "application/vnd.autodesk.fbx": ["fbx"],
75
- "application/vnd.balsamiq.bmml+xml": ["bmml"],
76
- "application/vnd.blueice.multipass": ["mpm"],
77
- "application/vnd.bmi": ["bmi"],
78
- "application/vnd.businessobjects": ["rep"],
79
- "application/vnd.chemdraw+xml": ["cdxml"],
80
- "application/vnd.chipnuts.karaoke-mmd": ["mmd"],
81
- "application/vnd.cinderella": ["cdy"],
82
- "application/vnd.citationstyles.style+xml": ["csl"],
83
- "application/vnd.claymore": ["cla"],
84
- "application/vnd.cloanto.rp9": ["rp9"],
85
- "application/vnd.clonk.c4group": [
86
- "c4g",
87
- "c4d",
88
- "c4f",
89
- "c4p",
90
- "c4u"
91
- ],
92
- "application/vnd.cluetrust.cartomobile-config": ["c11amc"],
93
- "application/vnd.cluetrust.cartomobile-config-pkg": ["c11amz"],
94
- "application/vnd.commonspace": ["csp"],
95
- "application/vnd.contact.cmsg": ["cdbcmsg"],
96
- "application/vnd.cosmocaller": ["cmc"],
97
- "application/vnd.crick.clicker": ["clkx"],
98
- "application/vnd.crick.clicker.keyboard": ["clkk"],
99
- "application/vnd.crick.clicker.palette": ["clkp"],
100
- "application/vnd.crick.clicker.template": ["clkt"],
101
- "application/vnd.crick.clicker.wordbank": ["clkw"],
102
- "application/vnd.criticaltools.wbs+xml": ["wbs"],
103
- "application/vnd.ctc-posml": ["pml"],
104
- "application/vnd.cups-ppd": ["ppd"],
105
- "application/vnd.curl.car": ["car"],
106
- "application/vnd.curl.pcurl": ["pcurl"],
107
- "application/vnd.dart": ["dart"],
108
- "application/vnd.data-vision.rdz": ["rdz"],
109
- "application/vnd.dbf": ["dbf"],
110
- "application/vnd.dcmp+xml": ["dcmp"],
111
- "application/vnd.dece.data": [
112
- "uvf",
113
- "uvvf",
114
- "uvd",
115
- "uvvd"
116
- ],
117
- "application/vnd.dece.ttml+xml": ["uvt", "uvvt"],
118
- "application/vnd.dece.unspecified": ["uvx", "uvvx"],
119
- "application/vnd.dece.zip": ["uvz", "uvvz"],
120
- "application/vnd.denovo.fcselayout-link": ["fe_launch"],
121
- "application/vnd.dna": ["dna"],
122
- "application/vnd.dolby.mlp": ["mlp"],
123
- "application/vnd.dpgraph": ["dpg"],
124
- "application/vnd.dreamfactory": ["dfac"],
125
- "application/vnd.ds-keypoint": ["kpxx"],
126
- "application/vnd.dvb.ait": ["ait"],
127
- "application/vnd.dvb.service": ["svc"],
128
- "application/vnd.dynageo": ["geo"],
129
- "application/vnd.ecowin.chart": ["mag"],
130
- "application/vnd.enliven": ["nml"],
131
- "application/vnd.epson.esf": ["esf"],
132
- "application/vnd.epson.msf": ["msf"],
133
- "application/vnd.epson.quickanime": ["qam"],
134
- "application/vnd.epson.salt": ["slt"],
135
- "application/vnd.epson.ssf": ["ssf"],
136
- "application/vnd.eszigno3+xml": ["es3", "et3"],
137
- "application/vnd.ezpix-album": ["ez2"],
138
- "application/vnd.ezpix-package": ["ez3"],
139
- "application/vnd.fdf": ["*fdf"],
140
- "application/vnd.fdsn.mseed": ["mseed"],
141
- "application/vnd.fdsn.seed": ["seed", "dataless"],
142
- "application/vnd.flographit": ["gph"],
143
- "application/vnd.fluxtime.clip": ["ftc"],
144
- "application/vnd.framemaker": [
145
- "fm",
146
- "frame",
147
- "maker",
148
- "book"
149
- ],
150
- "application/vnd.frogans.fnc": ["fnc"],
151
- "application/vnd.frogans.ltf": ["ltf"],
152
- "application/vnd.fsc.weblaunch": ["fsc"],
153
- "application/vnd.fujitsu.oasys": ["oas"],
154
- "application/vnd.fujitsu.oasys2": ["oa2"],
155
- "application/vnd.fujitsu.oasys3": ["oa3"],
156
- "application/vnd.fujitsu.oasysgp": ["fg5"],
157
- "application/vnd.fujitsu.oasysprs": ["bh2"],
158
- "application/vnd.fujixerox.ddd": ["ddd"],
159
- "application/vnd.fujixerox.docuworks": ["xdw"],
160
- "application/vnd.fujixerox.docuworks.binder": ["xbd"],
161
- "application/vnd.fuzzysheet": ["fzs"],
162
- "application/vnd.genomatix.tuxedo": ["txd"],
163
- "application/vnd.geogebra.file": ["ggb"],
164
- "application/vnd.geogebra.slides": ["ggs"],
165
- "application/vnd.geogebra.tool": ["ggt"],
166
- "application/vnd.geometry-explorer": ["gex", "gre"],
167
- "application/vnd.geonext": ["gxt"],
168
- "application/vnd.geoplan": ["g2w"],
169
- "application/vnd.geospace": ["g3w"],
170
- "application/vnd.gmx": ["gmx"],
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"],
176
- "application/vnd.google-apps.presentation": ["gslides"],
177
- "application/vnd.google-apps.script": ["gscript"],
178
- "application/vnd.google-apps.site": ["gsite"],
179
- "application/vnd.google-apps.spreadsheet": ["gsheet"],
180
- "application/vnd.google-earth.kml+xml": ["kml"],
181
- "application/vnd.google-earth.kmz": ["kmz"],
182
- "application/vnd.gov.sk.xmldatacontainer+xml": ["xdcf"],
183
- "application/vnd.grafeq": ["gqf", "gqs"],
184
- "application/vnd.groove-account": ["gac"],
185
- "application/vnd.groove-help": ["ghf"],
186
- "application/vnd.groove-identity-message": ["gim"],
187
- "application/vnd.groove-injector": ["grv"],
188
- "application/vnd.groove-tool-message": ["gtm"],
189
- "application/vnd.groove-tool-template": ["tpl"],
190
- "application/vnd.groove-vcard": ["vcg"],
191
- "application/vnd.hal+xml": ["hal"],
192
- "application/vnd.handheld-entertainment+xml": ["zmm"],
193
- "application/vnd.hbci": ["hbci"],
194
- "application/vnd.hhe.lesson-player": ["les"],
195
- "application/vnd.hp-hpgl": ["hpgl"],
196
- "application/vnd.hp-hpid": ["hpid"],
197
- "application/vnd.hp-hps": ["hps"],
198
- "application/vnd.hp-jlyt": ["jlt"],
199
- "application/vnd.hp-pcl": ["pcl"],
200
- "application/vnd.hp-pclxl": ["pclxl"],
201
- "application/vnd.hydrostatix.sof-data": ["sfd-hdstx"],
202
- "application/vnd.ibm.minipay": ["mpy"],
203
- "application/vnd.ibm.modcap": [
204
- "afp",
205
- "listafp",
206
- "list3820"
207
- ],
208
- "application/vnd.ibm.rights-management": ["irm"],
209
- "application/vnd.ibm.secure-container": ["sc"],
210
- "application/vnd.iccprofile": ["icc", "icm"],
211
- "application/vnd.igloader": ["igl"],
212
- "application/vnd.immervision-ivp": ["ivp"],
213
- "application/vnd.immervision-ivu": ["ivu"],
214
- "application/vnd.insors.igm": ["igm"],
215
- "application/vnd.intercon.formnet": ["xpw", "xpx"],
216
- "application/vnd.intergeo": ["i2g"],
217
- "application/vnd.intu.qbo": ["qbo"],
218
- "application/vnd.intu.qfx": ["qfx"],
219
- "application/vnd.ipunplugged.rcprofile": ["rcprofile"],
220
- "application/vnd.irepository.package+xml": ["irp"],
221
- "application/vnd.is-xpr": ["xpr"],
222
- "application/vnd.isac.fcs": ["fcs"],
223
- "application/vnd.jam": ["jam"],
224
- "application/vnd.jcp.javame.midlet-rms": ["rms"],
225
- "application/vnd.jisp": ["jisp"],
226
- "application/vnd.joost.joda-archive": ["joda"],
227
- "application/vnd.kahootz": ["ktz", "ktr"],
228
- "application/vnd.kde.karbon": ["karbon"],
229
- "application/vnd.kde.kchart": ["chrt"],
230
- "application/vnd.kde.kformula": ["kfo"],
231
- "application/vnd.kde.kivio": ["flw"],
232
- "application/vnd.kde.kontour": ["kon"],
233
- "application/vnd.kde.kpresenter": ["kpr", "kpt"],
234
- "application/vnd.kde.kspread": ["ksp"],
235
- "application/vnd.kde.kword": ["kwd", "kwt"],
236
- "application/vnd.kenameaapp": ["htke"],
237
- "application/vnd.kidspiration": ["kia"],
238
- "application/vnd.kinar": ["kne", "knp"],
239
- "application/vnd.koan": [
240
- "skp",
241
- "skd",
242
- "skt",
243
- "skm"
244
- ],
245
- "application/vnd.kodak-descriptor": ["sse"],
246
- "application/vnd.las.las+xml": ["lasxml"],
247
- "application/vnd.llamagraphics.life-balance.desktop": ["lbd"],
248
- "application/vnd.llamagraphics.life-balance.exchange+xml": ["lbe"],
249
- "application/vnd.lotus-1-2-3": ["123"],
250
- "application/vnd.lotus-approach": ["apr"],
251
- "application/vnd.lotus-freelance": ["pre"],
252
- "application/vnd.lotus-notes": ["nsf"],
253
- "application/vnd.lotus-organizer": ["org"],
254
- "application/vnd.lotus-screencam": ["scm"],
255
- "application/vnd.lotus-wordpro": ["lwp"],
256
- "application/vnd.macports.portpkg": ["portpkg"],
257
- "application/vnd.mapbox-vector-tile": ["mvt"],
258
- "application/vnd.mcd": ["mcd"],
259
- "application/vnd.medcalcdata": ["mc1"],
260
- "application/vnd.mediastation.cdkey": ["cdkey"],
261
- "application/vnd.mfer": ["mwf"],
262
- "application/vnd.mfmp": ["mfm"],
263
- "application/vnd.micrografx.flo": ["flo"],
264
- "application/vnd.micrografx.igx": ["igx"],
265
- "application/vnd.mif": ["mif"],
266
- "application/vnd.mobius.daf": ["daf"],
267
- "application/vnd.mobius.dis": ["dis"],
268
- "application/vnd.mobius.mbk": ["mbk"],
269
- "application/vnd.mobius.mqy": ["mqy"],
270
- "application/vnd.mobius.msl": ["msl"],
271
- "application/vnd.mobius.plc": ["plc"],
272
- "application/vnd.mobius.txf": ["txf"],
273
- "application/vnd.mophun.application": ["mpn"],
274
- "application/vnd.mophun.certificate": ["mpc"],
275
- "application/vnd.mozilla.xul+xml": ["xul"],
276
- "application/vnd.ms-artgalry": ["cil"],
277
- "application/vnd.ms-cab-compressed": ["cab"],
278
- "application/vnd.ms-excel": [
279
- "xls",
280
- "xlm",
281
- "xla",
282
- "xlc",
283
- "xlt",
284
- "xlw"
285
- ],
286
- "application/vnd.ms-excel.addin.macroenabled.12": ["xlam"],
287
- "application/vnd.ms-excel.sheet.binary.macroenabled.12": ["xlsb"],
288
- "application/vnd.ms-excel.sheet.macroenabled.12": ["xlsm"],
289
- "application/vnd.ms-excel.template.macroenabled.12": ["xltm"],
290
- "application/vnd.ms-fontobject": ["eot"],
291
- "application/vnd.ms-htmlhelp": ["chm"],
292
- "application/vnd.ms-ims": ["ims"],
293
- "application/vnd.ms-lrm": ["lrm"],
294
- "application/vnd.ms-officetheme": ["thmx"],
295
- "application/vnd.ms-outlook": ["msg"],
296
- "application/vnd.ms-pki.seccat": ["cat"],
297
- "application/vnd.ms-pki.stl": ["*stl"],
298
- "application/vnd.ms-powerpoint": [
299
- "ppt",
300
- "pps",
301
- "pot"
302
- ],
303
- "application/vnd.ms-powerpoint.addin.macroenabled.12": ["ppam"],
304
- "application/vnd.ms-powerpoint.presentation.macroenabled.12": ["pptm"],
305
- "application/vnd.ms-powerpoint.slide.macroenabled.12": ["sldm"],
306
- "application/vnd.ms-powerpoint.slideshow.macroenabled.12": ["ppsm"],
307
- "application/vnd.ms-powerpoint.template.macroenabled.12": ["potm"],
308
- "application/vnd.ms-project": ["*mpp", "mpt"],
309
- "application/vnd.ms-visio.viewer": ["vdx"],
310
- "application/vnd.ms-word.document.macroenabled.12": ["docm"],
311
- "application/vnd.ms-word.template.macroenabled.12": ["dotm"],
312
- "application/vnd.ms-works": [
313
- "wps",
314
- "wks",
315
- "wcm",
316
- "wdb"
317
- ],
318
- "application/vnd.ms-wpl": ["wpl"],
319
- "application/vnd.ms-xpsdocument": ["xps"],
320
- "application/vnd.mseq": ["mseq"],
321
- "application/vnd.musician": ["mus"],
322
- "application/vnd.muvee.style": ["msty"],
323
- "application/vnd.mynfc": ["taglet"],
324
- "application/vnd.nato.bindingdataobject+xml": ["bdo"],
325
- "application/vnd.neurolanguage.nlu": ["nlu"],
326
- "application/vnd.nitf": ["ntf", "nitf"],
327
- "application/vnd.noblenet-directory": ["nnd"],
328
- "application/vnd.noblenet-sealer": ["nns"],
329
- "application/vnd.noblenet-web": ["nnw"],
330
- "application/vnd.nokia.n-gage.ac+xml": ["*ac"],
331
- "application/vnd.nokia.n-gage.data": ["ngdat"],
332
- "application/vnd.nokia.n-gage.symbian.install": ["n-gage"],
333
- "application/vnd.nokia.radio-preset": ["rpst"],
334
- "application/vnd.nokia.radio-presets": ["rpss"],
335
- "application/vnd.novadigm.edm": ["edm"],
336
- "application/vnd.novadigm.edx": ["edx"],
337
- "application/vnd.novadigm.ext": ["ext"],
338
- "application/vnd.oasis.opendocument.chart": ["odc"],
339
- "application/vnd.oasis.opendocument.chart-template": ["otc"],
340
- "application/vnd.oasis.opendocument.database": ["odb"],
341
- "application/vnd.oasis.opendocument.formula": ["odf"],
342
- "application/vnd.oasis.opendocument.formula-template": ["odft"],
343
- "application/vnd.oasis.opendocument.graphics": ["odg"],
344
- "application/vnd.oasis.opendocument.graphics-template": ["otg"],
345
- "application/vnd.oasis.opendocument.image": ["odi"],
346
- "application/vnd.oasis.opendocument.image-template": ["oti"],
347
- "application/vnd.oasis.opendocument.presentation": ["odp"],
348
- "application/vnd.oasis.opendocument.presentation-template": ["otp"],
349
- "application/vnd.oasis.opendocument.spreadsheet": ["ods"],
350
- "application/vnd.oasis.opendocument.spreadsheet-template": ["ots"],
351
- "application/vnd.oasis.opendocument.text": ["odt"],
352
- "application/vnd.oasis.opendocument.text-master": ["odm"],
353
- "application/vnd.oasis.opendocument.text-template": ["ott"],
354
- "application/vnd.oasis.opendocument.text-web": ["oth"],
355
- "application/vnd.olpc-sugar": ["xo"],
356
- "application/vnd.oma.dd2+xml": ["dd2"],
357
- "application/vnd.openblox.game+xml": ["obgx"],
358
- "application/vnd.openofficeorg.extension": ["oxt"],
359
- "application/vnd.openstreetmap.data+xml": ["osm"],
360
- "application/vnd.openxmlformats-officedocument.presentationml.presentation": ["pptx"],
361
- "application/vnd.openxmlformats-officedocument.presentationml.slide": ["sldx"],
362
- "application/vnd.openxmlformats-officedocument.presentationml.slideshow": ["ppsx"],
363
- "application/vnd.openxmlformats-officedocument.presentationml.template": ["potx"],
364
- "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet": ["xlsx"],
365
- "application/vnd.openxmlformats-officedocument.spreadsheetml.template": ["xltx"],
366
- "application/vnd.openxmlformats-officedocument.wordprocessingml.document": ["docx"],
367
- "application/vnd.openxmlformats-officedocument.wordprocessingml.template": ["dotx"],
368
- "application/vnd.osgeo.mapguide.package": ["mgp"],
369
- "application/vnd.osgi.dp": ["dp"],
370
- "application/vnd.osgi.subsystem": ["esa"],
371
- "application/vnd.palm": [
372
- "pdb",
373
- "pqa",
374
- "oprc"
375
- ],
376
- "application/vnd.pawaafile": ["paw"],
377
- "application/vnd.pg.format": ["str"],
378
- "application/vnd.pg.osasli": ["ei6"],
379
- "application/vnd.picsel": ["efif"],
380
- "application/vnd.pmi.widget": ["wg"],
381
- "application/vnd.pocketlearn": ["plf"],
382
- "application/vnd.powerbuilder6": ["pbd"],
383
- "application/vnd.previewsystems.box": ["box"],
384
- "application/vnd.procrate.brushset": ["brushset"],
385
- "application/vnd.procreate.brush": ["brush"],
386
- "application/vnd.procreate.dream": ["drm"],
387
- "application/vnd.proteus.magazine": ["mgz"],
388
- "application/vnd.publishare-delta-tree": ["qps"],
389
- "application/vnd.pvi.ptid1": ["ptid"],
390
- "application/vnd.pwg-xhtml-print+xml": ["xhtm"],
391
- "application/vnd.quark.quarkxpress": [
392
- "qxd",
393
- "qxt",
394
- "qwd",
395
- "qwt",
396
- "qxl",
397
- "qxb"
398
- ],
399
- "application/vnd.rar": ["rar"],
400
- "application/vnd.realvnc.bed": ["bed"],
401
- "application/vnd.recordare.musicxml": ["mxl"],
402
- "application/vnd.recordare.musicxml+xml": ["musicxml"],
403
- "application/vnd.rig.cryptonote": ["cryptonote"],
404
- "application/vnd.rim.cod": ["cod"],
405
- "application/vnd.rn-realmedia": ["rm"],
406
- "application/vnd.rn-realmedia-vbr": ["rmvb"],
407
- "application/vnd.route66.link66+xml": ["link66"],
408
- "application/vnd.sailingtracker.track": ["st"],
409
- "application/vnd.seemail": ["see"],
410
- "application/vnd.sema": ["sema"],
411
- "application/vnd.semd": ["semd"],
412
- "application/vnd.semf": ["semf"],
413
- "application/vnd.shana.informed.formdata": ["ifm"],
414
- "application/vnd.shana.informed.formtemplate": ["itp"],
415
- "application/vnd.shana.informed.interchange": ["iif"],
416
- "application/vnd.shana.informed.package": ["ipk"],
417
- "application/vnd.simtech-mindmapper": ["twd", "twds"],
418
- "application/vnd.smaf": ["mmf"],
419
- "application/vnd.smart.teacher": ["teacher"],
420
- "application/vnd.software602.filler.form+xml": ["fo"],
421
- "application/vnd.solent.sdkm+xml": ["sdkm", "sdkd"],
422
- "application/vnd.spotfire.dxp": ["dxp"],
423
- "application/vnd.spotfire.sfs": ["sfs"],
424
- "application/vnd.stardivision.calc": ["sdc"],
425
- "application/vnd.stardivision.draw": ["sda"],
426
- "application/vnd.stardivision.impress": ["sdd"],
427
- "application/vnd.stardivision.math": ["smf"],
428
- "application/vnd.stardivision.writer": ["sdw", "vor"],
429
- "application/vnd.stardivision.writer-global": ["sgl"],
430
- "application/vnd.stepmania.package": ["smzip"],
431
- "application/vnd.stepmania.stepchart": ["sm"],
432
- "application/vnd.sun.wadl+xml": ["wadl"],
433
- "application/vnd.sun.xml.calc": ["sxc"],
434
- "application/vnd.sun.xml.calc.template": ["stc"],
435
- "application/vnd.sun.xml.draw": ["sxd"],
436
- "application/vnd.sun.xml.draw.template": ["std"],
437
- "application/vnd.sun.xml.impress": ["sxi"],
438
- "application/vnd.sun.xml.impress.template": ["sti"],
439
- "application/vnd.sun.xml.math": ["sxm"],
440
- "application/vnd.sun.xml.writer": ["sxw"],
441
- "application/vnd.sun.xml.writer.global": ["sxg"],
442
- "application/vnd.sun.xml.writer.template": ["stw"],
443
- "application/vnd.sus-calendar": ["sus", "susp"],
444
- "application/vnd.svd": ["svd"],
445
- "application/vnd.symbian.install": ["sis", "sisx"],
446
- "application/vnd.syncml+xml": ["xsm"],
447
- "application/vnd.syncml.dm+wbxml": ["bdm"],
448
- "application/vnd.syncml.dm+xml": ["xdm"],
449
- "application/vnd.syncml.dmddf+xml": ["ddf"],
450
- "application/vnd.tao.intent-module-archive": ["tao"],
451
- "application/vnd.tcpdump.pcap": [
452
- "pcap",
453
- "cap",
454
- "dmp"
455
- ],
456
- "application/vnd.tmobile-livetv": ["tmo"],
457
- "application/vnd.trid.tpt": ["tpt"],
458
- "application/vnd.triscape.mxs": ["mxs"],
459
- "application/vnd.trueapp": ["tra"],
460
- "application/vnd.ufdl": ["ufd", "ufdl"],
461
- "application/vnd.uiq.theme": ["utz"],
462
- "application/vnd.umajin": ["umj"],
463
- "application/vnd.unity": ["unityweb"],
464
- "application/vnd.uoml+xml": ["uoml", "uo"],
465
- "application/vnd.vcx": ["vcx"],
466
- "application/vnd.visio": [
467
- "vsd",
468
- "vst",
469
- "vss",
470
- "vsw",
471
- "vsdx",
472
- "vtx"
473
- ],
474
- "application/vnd.visionary": ["vis"],
475
- "application/vnd.vsf": ["vsf"],
476
- "application/vnd.wap.wbxml": ["wbxml"],
477
- "application/vnd.wap.wmlc": ["wmlc"],
478
- "application/vnd.wap.wmlscriptc": ["wmlsc"],
479
- "application/vnd.webturbo": ["wtb"],
480
- "application/vnd.wolfram.player": ["nbp"],
481
- "application/vnd.wordperfect": ["wpd"],
482
- "application/vnd.wqd": ["wqd"],
483
- "application/vnd.wt.stf": ["stf"],
484
- "application/vnd.xara": ["xar"],
485
- "application/vnd.xfdl": ["xfdl"],
486
- "application/vnd.yamaha.hv-dic": ["hvd"],
487
- "application/vnd.yamaha.hv-script": ["hvs"],
488
- "application/vnd.yamaha.hv-voice": ["hvp"],
489
- "application/vnd.yamaha.openscoreformat": ["osf"],
490
- "application/vnd.yamaha.openscoreformat.osfpvg+xml": ["osfpvg"],
491
- "application/vnd.yamaha.smaf-audio": ["saf"],
492
- "application/vnd.yamaha.smaf-phrase": ["spf"],
493
- "application/vnd.yellowriver-custom-menu": ["cmp"],
494
- "application/vnd.zul": ["zir", "zirz"],
495
- "application/vnd.zzazz.deck+xml": ["zaz"],
496
- "application/x-7z-compressed": ["7z"],
497
- "application/x-abiword": ["abw"],
498
- "application/x-ace-compressed": ["ace"],
499
- "application/x-apple-diskimage": ["*dmg"],
500
- "application/x-arj": ["arj"],
501
- "application/x-authorware-bin": [
502
- "aab",
503
- "x32",
504
- "u32",
505
- "vox"
506
- ],
507
- "application/x-authorware-map": ["aam"],
508
- "application/x-authorware-seg": ["aas"],
509
- "application/x-bcpio": ["bcpio"],
510
- "application/x-bdoc": ["*bdoc"],
511
- "application/x-bittorrent": ["torrent"],
512
- "application/x-blender": ["blend"],
513
- "application/x-blorb": ["blb", "blorb"],
514
- "application/x-bzip": ["bz"],
515
- "application/x-bzip2": ["bz2", "boz"],
516
- "application/x-cbr": [
517
- "cbr",
518
- "cba",
519
- "cbt",
520
- "cbz",
521
- "cb7"
522
- ],
523
- "application/x-cdlink": ["vcd"],
524
- "application/x-cfs-compressed": ["cfs"],
525
- "application/x-chat": ["chat"],
526
- "application/x-chess-pgn": ["pgn"],
527
- "application/x-chrome-extension": ["crx"],
528
- "application/x-cocoa": ["cco"],
529
- "application/x-compressed": ["*rar"],
530
- "application/x-conference": ["nsc"],
531
- "application/x-cpio": ["cpio"],
532
- "application/x-csh": ["csh"],
533
- "application/x-debian-package": ["*deb", "udeb"],
534
- "application/x-dgc-compressed": ["dgc"],
535
- "application/x-director": [
536
- "dir",
537
- "dcr",
538
- "dxr",
539
- "cst",
540
- "cct",
541
- "cxt",
542
- "w3d",
543
- "fgd",
544
- "swa"
545
- ],
546
- "application/x-doom": ["wad"],
547
- "application/x-dtbncx+xml": ["ncx"],
548
- "application/x-dtbook+xml": ["dtb"],
549
- "application/x-dtbresource+xml": ["res"],
550
- "application/x-dvi": ["dvi"],
551
- "application/x-envoy": ["evy"],
552
- "application/x-eva": ["eva"],
553
- "application/x-font-bdf": ["bdf"],
554
- "application/x-font-ghostscript": ["gsf"],
555
- "application/x-font-linux-psf": ["psf"],
556
- "application/x-font-pcf": ["pcf"],
557
- "application/x-font-snf": ["snf"],
558
- "application/x-font-type1": [
559
- "pfa",
560
- "pfb",
561
- "pfm",
562
- "afm"
563
- ],
564
- "application/x-freearc": ["arc"],
565
- "application/x-futuresplash": ["spl"],
566
- "application/x-gca-compressed": ["gca"],
567
- "application/x-glulx": ["ulx"],
568
- "application/x-gnumeric": ["gnumeric"],
569
- "application/x-gramps-xml": ["gramps"],
570
- "application/x-gtar": ["gtar"],
571
- "application/x-hdf": ["hdf"],
572
- "application/x-httpd-php": ["php"],
573
- "application/x-install-instructions": ["install"],
574
- "application/x-ipynb+json": ["ipynb"],
575
- "application/x-iso9660-image": ["*iso"],
576
- "application/x-iwork-keynote-sffkey": ["*key"],
577
- "application/x-iwork-numbers-sffnumbers": ["*numbers"],
578
- "application/x-iwork-pages-sffpages": ["*pages"],
579
- "application/x-java-archive-diff": ["jardiff"],
580
- "application/x-java-jnlp-file": ["jnlp"],
581
- "application/x-keepass2": ["kdbx"],
582
- "application/x-latex": ["latex"],
583
- "application/x-lua-bytecode": ["luac"],
584
- "application/x-lzh-compressed": ["lzh", "lha"],
585
- "application/x-makeself": ["run"],
586
- "application/x-mie": ["mie"],
587
- "application/x-mobipocket-ebook": ["*prc", "mobi"],
588
- "application/x-ms-application": ["application"],
589
- "application/x-ms-shortcut": ["lnk"],
590
- "application/x-ms-wmd": ["wmd"],
591
- "application/x-ms-wmz": ["wmz"],
592
- "application/x-ms-xbap": ["xbap"],
593
- "application/x-msaccess": ["mdb"],
594
- "application/x-msbinder": ["obd"],
595
- "application/x-mscardfile": ["crd"],
596
- "application/x-msclip": ["clp"],
597
- "application/x-msdos-program": ["*exe"],
598
- "application/x-msdownload": [
599
- "*exe",
600
- "*dll",
601
- "com",
602
- "bat",
603
- "*msi"
604
- ],
605
- "application/x-msmediaview": [
606
- "mvb",
607
- "m13",
608
- "m14"
609
- ],
610
- "application/x-msmetafile": [
611
- "*wmf",
612
- "*wmz",
613
- "*emf",
614
- "emz"
615
- ],
616
- "application/x-msmoney": ["mny"],
617
- "application/x-mspublisher": ["pub"],
618
- "application/x-msschedule": ["scd"],
619
- "application/x-msterminal": ["trm"],
620
- "application/x-mswrite": ["wri"],
621
- "application/x-netcdf": ["nc", "cdf"],
622
- "application/x-ns-proxy-autoconfig": ["pac"],
623
- "application/x-nzb": ["nzb"],
624
- "application/x-perl": ["pl", "pm"],
625
- "application/x-pilot": ["*prc", "*pdb"],
626
- "application/x-pkcs12": ["p12", "pfx"],
627
- "application/x-pkcs7-certificates": ["p7b", "spc"],
628
- "application/x-pkcs7-certreqresp": ["p7r"],
629
- "application/x-rar-compressed": ["*rar"],
630
- "application/x-redhat-package-manager": ["rpm"],
631
- "application/x-research-info-systems": ["ris"],
632
- "application/x-sea": ["sea"],
633
- "application/x-sh": ["sh"],
634
- "application/x-shar": ["shar"],
635
- "application/x-shockwave-flash": ["swf"],
636
- "application/x-silverlight-app": ["xap"],
637
- "application/x-sql": ["*sql"],
638
- "application/x-stuffit": ["sit"],
639
- "application/x-stuffitx": ["sitx"],
640
- "application/x-subrip": ["srt"],
641
- "application/x-sv4cpio": ["sv4cpio"],
642
- "application/x-sv4crc": ["sv4crc"],
643
- "application/x-t3vm-image": ["t3"],
644
- "application/x-tads": ["gam"],
645
- "application/x-tar": ["tar"],
646
- "application/x-tcl": ["tcl", "tk"],
647
- "application/x-tex": ["tex"],
648
- "application/x-tex-tfm": ["tfm"],
649
- "application/x-texinfo": ["texinfo", "texi"],
650
- "application/x-tgif": ["*obj"],
651
- "application/x-ustar": ["ustar"],
652
- "application/x-virtualbox-hdd": ["hdd"],
653
- "application/x-virtualbox-ova": ["ova"],
654
- "application/x-virtualbox-ovf": ["ovf"],
655
- "application/x-virtualbox-vbox": ["vbox"],
656
- "application/x-virtualbox-vbox-extpack": ["vbox-extpack"],
657
- "application/x-virtualbox-vdi": ["vdi"],
658
- "application/x-virtualbox-vhd": ["vhd"],
659
- "application/x-virtualbox-vmdk": ["vmdk"],
660
- "application/x-wais-source": ["src"],
661
- "application/x-web-app-manifest+json": ["webapp"],
662
- "application/x-x509-ca-cert": [
663
- "der",
664
- "crt",
665
- "pem"
666
- ],
667
- "application/x-xfig": ["fig"],
668
- "application/x-xliff+xml": ["*xlf"],
669
- "application/x-xpinstall": ["xpi"],
670
- "application/x-xz": ["xz"],
671
- "application/x-zip-compressed": ["*zip"],
672
- "application/x-zmachine": [
673
- "z1",
674
- "z2",
675
- "z3",
676
- "z4",
677
- "z5",
678
- "z6",
679
- "z7",
680
- "z8"
681
- ],
682
- "audio/vnd.dece.audio": ["uva", "uvva"],
683
- "audio/vnd.digital-winds": ["eol"],
684
- "audio/vnd.dra": ["dra"],
685
- "audio/vnd.dts": ["dts"],
686
- "audio/vnd.dts.hd": ["dtshd"],
687
- "audio/vnd.lucent.voice": ["lvp"],
688
- "audio/vnd.ms-playready.media.pya": ["pya"],
689
- "audio/vnd.nuera.ecelp4800": ["ecelp4800"],
690
- "audio/vnd.nuera.ecelp7470": ["ecelp7470"],
691
- "audio/vnd.nuera.ecelp9600": ["ecelp9600"],
692
- "audio/vnd.rip": ["rip"],
693
- "audio/x-aac": ["*aac"],
694
- "audio/x-aiff": [
695
- "aif",
696
- "aiff",
697
- "aifc"
698
- ],
699
- "audio/x-caf": ["caf"],
700
- "audio/x-flac": ["flac"],
701
- "audio/x-m4a": ["*m4a"],
702
- "audio/x-matroska": ["mka"],
703
- "audio/x-mpegurl": ["m3u"],
704
- "audio/x-ms-wax": ["wax"],
705
- "audio/x-ms-wma": ["wma"],
706
- "audio/x-pn-realaudio": ["ram", "ra"],
707
- "audio/x-pn-realaudio-plugin": ["rmp"],
708
- "audio/x-realaudio": ["*ra"],
709
- "audio/x-wav": ["*wav"],
710
- "chemical/x-cdx": ["cdx"],
711
- "chemical/x-cif": ["cif"],
712
- "chemical/x-cmdf": ["cmdf"],
713
- "chemical/x-cml": ["cml"],
714
- "chemical/x-csml": ["csml"],
715
- "chemical/x-xyz": ["xyz"],
716
- "image/prs.btif": ["btif", "btf"],
717
- "image/prs.pti": ["pti"],
718
- "image/vnd.adobe.photoshop": ["psd"],
719
- "image/vnd.airzip.accelerator.azv": ["azv"],
720
- "image/vnd.blockfact.facti": ["facti"],
721
- "image/vnd.dece.graphic": [
722
- "uvi",
723
- "uvvi",
724
- "uvg",
725
- "uvvg"
726
- ],
727
- "image/vnd.djvu": ["djvu", "djv"],
728
- "image/vnd.dvb.subtitle": ["*sub"],
729
- "image/vnd.dwg": ["dwg"],
730
- "image/vnd.dxf": ["dxf"],
731
- "image/vnd.fastbidsheet": ["fbs"],
732
- "image/vnd.fpx": ["fpx"],
733
- "image/vnd.fst": ["fst"],
734
- "image/vnd.fujixerox.edmics-mmr": ["mmr"],
735
- "image/vnd.fujixerox.edmics-rlc": ["rlc"],
736
- "image/vnd.microsoft.icon": ["ico"],
737
- "image/vnd.ms-dds": ["dds"],
738
- "image/vnd.ms-modi": ["mdi"],
739
- "image/vnd.ms-photo": ["wdp"],
740
- "image/vnd.net-fpx": ["npx"],
741
- "image/vnd.pco.b16": ["b16"],
742
- "image/vnd.tencent.tap": ["tap"],
743
- "image/vnd.valve.source.texture": ["vtf"],
744
- "image/vnd.wap.wbmp": ["wbmp"],
745
- "image/vnd.xiff": ["xif"],
746
- "image/vnd.zbrush.pcx": ["pcx"],
747
- "image/x-3ds": ["3ds"],
748
- "image/x-adobe-dng": ["dng"],
749
- "image/x-cmu-raster": ["ras"],
750
- "image/x-cmx": ["cmx"],
751
- "image/x-freehand": [
752
- "fh",
753
- "fhc",
754
- "fh4",
755
- "fh5",
756
- "fh7"
757
- ],
758
- "image/x-icon": ["*ico"],
759
- "image/x-jng": ["jng"],
760
- "image/x-mrsid-image": ["sid"],
761
- "image/x-ms-bmp": ["*bmp"],
762
- "image/x-pcx": ["*pcx"],
763
- "image/x-pict": ["pic", "pct"],
764
- "image/x-portable-anymap": ["pnm"],
765
- "image/x-portable-bitmap": ["pbm"],
766
- "image/x-portable-graymap": ["pgm"],
767
- "image/x-portable-pixmap": ["ppm"],
768
- "image/x-rgb": ["rgb"],
769
- "image/x-tga": ["tga"],
770
- "image/x-xbitmap": ["xbm"],
771
- "image/x-xpixmap": ["xpm"],
772
- "image/x-xwindowdump": ["xwd"],
773
- "message/vnd.wfa.wsc": ["wsc"],
774
- "model/vnd.bary": ["bary"],
775
- "model/vnd.cld": ["cld"],
776
- "model/vnd.collada+xml": ["dae"],
777
- "model/vnd.dwf": ["dwf"],
778
- "model/vnd.gdl": ["gdl"],
779
- "model/vnd.gtw": ["gtw"],
780
- "model/vnd.mts": ["*mts"],
781
- "model/vnd.opengex": ["ogex"],
782
- "model/vnd.parasolid.transmit.binary": ["x_b"],
783
- "model/vnd.parasolid.transmit.text": ["x_t"],
784
- "model/vnd.pytha.pyox": ["pyo", "pyox"],
785
- "model/vnd.sap.vds": ["vds"],
786
- "model/vnd.usda": ["usda"],
787
- "model/vnd.usdz+zip": ["usdz"],
788
- "model/vnd.valve.source.compiled-map": ["bsp"],
789
- "model/vnd.vtu": ["vtu"],
790
- "text/prs.lines.tag": ["dsc"],
791
- "text/vnd.curl": ["curl"],
792
- "text/vnd.curl.dcurl": ["dcurl"],
793
- "text/vnd.curl.mcurl": ["mcurl"],
794
- "text/vnd.curl.scurl": ["scurl"],
795
- "text/vnd.dvb.subtitle": ["sub"],
796
- "text/vnd.familysearch.gedcom": ["ged"],
797
- "text/vnd.fly": ["fly"],
798
- "text/vnd.fmi.flexstor": ["flx"],
799
- "text/vnd.graphviz": ["gv"],
800
- "text/vnd.in3d.3dml": ["3dml"],
801
- "text/vnd.in3d.spot": ["spot"],
802
- "text/vnd.sun.j2me.app-descriptor": ["jad"],
803
- "text/vnd.wap.wml": ["wml"],
804
- "text/vnd.wap.wmlscript": ["wmls"],
805
- "text/x-asm": ["s", "asm"],
806
- "text/x-c": [
807
- "c",
808
- "cc",
809
- "cxx",
810
- "cpp",
811
- "h",
812
- "hh",
813
- "dic"
814
- ],
815
- "text/x-component": ["htc"],
816
- "text/x-fortran": [
817
- "f",
818
- "for",
819
- "f77",
820
- "f90"
821
- ],
822
- "text/x-handlebars-template": ["hbs"],
823
- "text/x-java-source": ["java"],
824
- "text/x-lua": ["lua"],
825
- "text/x-markdown": ["mkd"],
826
- "text/x-nfo": ["nfo"],
827
- "text/x-opml": ["opml"],
828
- "text/x-org": ["*org"],
829
- "text/x-pascal": ["p", "pas"],
830
- "text/x-processing": ["pde"],
831
- "text/x-sass": ["sass"],
832
- "text/x-scss": ["scss"],
833
- "text/x-setext": ["etx"],
834
- "text/x-sfv": ["sfv"],
835
- "text/x-suse-ymp": ["ymp"],
836
- "text/x-uuencode": ["uu"],
837
- "text/x-vcalendar": ["vcs"],
838
- "text/x-vcard": ["vcf"],
839
- "video/vnd.dece.hd": ["uvh", "uvvh"],
840
- "video/vnd.dece.mobile": ["uvm", "uvvm"],
841
- "video/vnd.dece.pd": ["uvp", "uvvp"],
842
- "video/vnd.dece.sd": ["uvs", "uvvs"],
843
- "video/vnd.dece.video": ["uvv", "uvvv"],
844
- "video/vnd.dvb.file": ["dvb"],
845
- "video/vnd.fvt": ["fvt"],
846
- "video/vnd.mpegurl": ["mxu", "m4u"],
847
- "video/vnd.ms-playready.media.pyv": ["pyv"],
848
- "video/vnd.uvvu.mp4": ["uvu", "uvvu"],
849
- "video/vnd.vivo": ["viv"],
850
- "video/x-f4v": ["f4v"],
851
- "video/x-fli": ["fli"],
852
- "video/x-flv": ["flv"],
853
- "video/x-m4v": ["m4v"],
854
- "video/x-matroska": [
855
- "mkv",
856
- "mk3d",
857
- "mks"
858
- ],
859
- "video/x-mng": ["mng"],
860
- "video/x-ms-asf": ["asf", "asx"],
861
- "video/x-ms-vob": ["vob"],
862
- "video/x-ms-wm": ["wm"],
863
- "video/x-ms-wmv": ["wmv"],
864
- "video/x-ms-wmx": ["wmx"],
865
- "video/x-ms-wvx": ["wvx"],
866
- "video/x-msvideo": ["avi"],
867
- "video/x-sgi-movie": ["movie"],
868
- "video/x-smv": ["smv"],
869
- "x-conference/x-cooltalk": ["ice"]
870
- };
871
- Object.freeze(types$1);
872
- //#endregion
873
- //#region ../../node_modules/.pnpm/mime@4.1.0/node_modules/mime/dist/types/standard.js
874
- const types = {
875
- "application/andrew-inset": ["ez"],
876
- "application/appinstaller": ["appinstaller"],
877
- "application/applixware": ["aw"],
878
- "application/appx": ["appx"],
879
- "application/appxbundle": ["appxbundle"],
880
- "application/atom+xml": ["atom"],
881
- "application/atomcat+xml": ["atomcat"],
882
- "application/atomdeleted+xml": ["atomdeleted"],
883
- "application/atomsvc+xml": ["atomsvc"],
884
- "application/atsc-dwd+xml": ["dwd"],
885
- "application/atsc-held+xml": ["held"],
886
- "application/atsc-rsat+xml": ["rsat"],
887
- "application/automationml-aml+xml": ["aml"],
888
- "application/automationml-amlx+zip": ["amlx"],
889
- "application/bdoc": ["bdoc"],
890
- "application/calendar+xml": ["xcs"],
891
- "application/ccxml+xml": ["ccxml"],
892
- "application/cdfx+xml": ["cdfx"],
893
- "application/cdmi-capability": ["cdmia"],
894
- "application/cdmi-container": ["cdmic"],
895
- "application/cdmi-domain": ["cdmid"],
896
- "application/cdmi-object": ["cdmio"],
897
- "application/cdmi-queue": ["cdmiq"],
898
- "application/cpl+xml": ["cpl"],
899
- "application/cu-seeme": ["cu"],
900
- "application/cwl": ["cwl"],
901
- "application/dash+xml": ["mpd"],
902
- "application/dash-patch+xml": ["mpp"],
903
- "application/davmount+xml": ["davmount"],
904
- "application/dicom": ["dcm"],
905
- "application/docbook+xml": ["dbk"],
906
- "application/dssc+der": ["dssc"],
907
- "application/dssc+xml": ["xdssc"],
908
- "application/ecmascript": ["ecma"],
909
- "application/emma+xml": ["emma"],
910
- "application/emotionml+xml": ["emotionml"],
911
- "application/epub+zip": ["epub"],
912
- "application/exi": ["exi"],
913
- "application/express": ["exp"],
914
- "application/fdf": ["fdf"],
915
- "application/fdt+xml": ["fdt"],
916
- "application/font-tdpfr": ["pfr"],
917
- "application/geo+json": ["geojson"],
918
- "application/gml+xml": ["gml"],
919
- "application/gpx+xml": ["gpx"],
920
- "application/gxf": ["gxf"],
921
- "application/gzip": ["gz"],
922
- "application/hjson": ["hjson"],
923
- "application/hyperstudio": ["stk"],
924
- "application/inkml+xml": ["ink", "inkml"],
925
- "application/ipfix": ["ipfix"],
926
- "application/its+xml": ["its"],
927
- "application/java-archive": [
928
- "jar",
929
- "war",
930
- "ear"
931
- ],
932
- "application/java-serialized-object": ["ser"],
933
- "application/java-vm": ["class"],
934
- "application/javascript": ["*js"],
935
- "application/json": ["json", "map"],
936
- "application/json5": ["json5"],
937
- "application/jsonml+json": ["jsonml"],
938
- "application/ld+json": ["jsonld"],
939
- "application/lgr+xml": ["lgr"],
940
- "application/lost+xml": ["lostxml"],
941
- "application/mac-binhex40": ["hqx"],
942
- "application/mac-compactpro": ["cpt"],
943
- "application/mads+xml": ["mads"],
944
- "application/manifest+json": ["webmanifest"],
945
- "application/marc": ["mrc"],
946
- "application/marcxml+xml": ["mrcx"],
947
- "application/mathematica": [
948
- "ma",
949
- "nb",
950
- "mb"
951
- ],
952
- "application/mathml+xml": ["mathml"],
953
- "application/mbox": ["mbox"],
954
- "application/media-policy-dataset+xml": ["mpf"],
955
- "application/mediaservercontrol+xml": ["mscml"],
956
- "application/metalink+xml": ["metalink"],
957
- "application/metalink4+xml": ["meta4"],
958
- "application/mets+xml": ["mets"],
959
- "application/mmt-aei+xml": ["maei"],
960
- "application/mmt-usd+xml": ["musd"],
961
- "application/mods+xml": ["mods"],
962
- "application/mp21": ["m21", "mp21"],
963
- "application/mp4": [
964
- "*mp4",
965
- "*mpg4",
966
- "mp4s",
967
- "m4p"
968
- ],
969
- "application/msix": ["msix"],
970
- "application/msixbundle": ["msixbundle"],
971
- "application/msword": ["doc", "dot"],
972
- "application/mxf": ["mxf"],
973
- "application/n-quads": ["nq"],
974
- "application/n-triples": ["nt"],
975
- "application/node": ["cjs"],
976
- "application/octet-stream": [
977
- "bin",
978
- "dms",
979
- "lrf",
980
- "mar",
981
- "so",
982
- "dist",
983
- "distz",
984
- "pkg",
985
- "bpk",
986
- "dump",
987
- "elc",
988
- "deploy",
989
- "exe",
990
- "dll",
991
- "deb",
992
- "dmg",
993
- "iso",
994
- "img",
995
- "msi",
996
- "msp",
997
- "msm",
998
- "buffer"
999
- ],
1000
- "application/oda": ["oda"],
1001
- "application/oebps-package+xml": ["opf"],
1002
- "application/ogg": ["ogx"],
1003
- "application/omdoc+xml": ["omdoc"],
1004
- "application/onenote": [
1005
- "onetoc",
1006
- "onetoc2",
1007
- "onetmp",
1008
- "onepkg",
1009
- "one",
1010
- "onea"
1011
- ],
1012
- "application/oxps": ["oxps"],
1013
- "application/p2p-overlay+xml": ["relo"],
1014
- "application/patch-ops-error+xml": ["xer"],
1015
- "application/pdf": ["pdf"],
1016
- "application/pgp-encrypted": ["pgp"],
1017
- "application/pgp-keys": ["asc"],
1018
- "application/pgp-signature": ["sig", "*asc"],
1019
- "application/pics-rules": ["prf"],
1020
- "application/pkcs10": ["p10"],
1021
- "application/pkcs7-mime": ["p7m", "p7c"],
1022
- "application/pkcs7-signature": ["p7s"],
1023
- "application/pkcs8": ["p8"],
1024
- "application/pkix-attr-cert": ["ac"],
1025
- "application/pkix-cert": ["cer"],
1026
- "application/pkix-crl": ["crl"],
1027
- "application/pkix-pkipath": ["pkipath"],
1028
- "application/pkixcmp": ["pki"],
1029
- "application/pls+xml": ["pls"],
1030
- "application/postscript": [
1031
- "ai",
1032
- "eps",
1033
- "ps"
1034
- ],
1035
- "application/provenance+xml": ["provx"],
1036
- "application/pskc+xml": ["pskcxml"],
1037
- "application/raml+yaml": ["raml"],
1038
- "application/rdf+xml": ["rdf", "owl"],
1039
- "application/reginfo+xml": ["rif"],
1040
- "application/relax-ng-compact-syntax": ["rnc"],
1041
- "application/resource-lists+xml": ["rl"],
1042
- "application/resource-lists-diff+xml": ["rld"],
1043
- "application/rls-services+xml": ["rs"],
1044
- "application/route-apd+xml": ["rapd"],
1045
- "application/route-s-tsid+xml": ["sls"],
1046
- "application/route-usd+xml": ["rusd"],
1047
- "application/rpki-ghostbusters": ["gbr"],
1048
- "application/rpki-manifest": ["mft"],
1049
- "application/rpki-roa": ["roa"],
1050
- "application/rsd+xml": ["rsd"],
1051
- "application/rss+xml": ["rss"],
1052
- "application/rtf": ["rtf"],
1053
- "application/sbml+xml": ["sbml"],
1054
- "application/scvp-cv-request": ["scq"],
1055
- "application/scvp-cv-response": ["scs"],
1056
- "application/scvp-vp-request": ["spq"],
1057
- "application/scvp-vp-response": ["spp"],
1058
- "application/sdp": ["sdp"],
1059
- "application/senml+xml": ["senmlx"],
1060
- "application/sensml+xml": ["sensmlx"],
1061
- "application/set-payment-initiation": ["setpay"],
1062
- "application/set-registration-initiation": ["setreg"],
1063
- "application/shf+xml": ["shf"],
1064
- "application/sieve": ["siv", "sieve"],
1065
- "application/smil+xml": ["smi", "smil"],
1066
- "application/sparql-query": ["rq"],
1067
- "application/sparql-results+xml": ["srx"],
1068
- "application/sql": ["sql"],
1069
- "application/srgs": ["gram"],
1070
- "application/srgs+xml": ["grxml"],
1071
- "application/sru+xml": ["sru"],
1072
- "application/ssdl+xml": ["ssdl"],
1073
- "application/ssml+xml": ["ssml"],
1074
- "application/swid+xml": ["swidtag"],
1075
- "application/tei+xml": ["tei", "teicorpus"],
1076
- "application/thraud+xml": ["tfi"],
1077
- "application/timestamped-data": ["tsd"],
1078
- "application/toml": ["toml"],
1079
- "application/trig": ["trig"],
1080
- "application/ttml+xml": ["ttml"],
1081
- "application/ubjson": ["ubj"],
1082
- "application/urc-ressheet+xml": ["rsheet"],
1083
- "application/urc-targetdesc+xml": ["td"],
1084
- "application/voicexml+xml": ["vxml"],
1085
- "application/wasm": ["wasm"],
1086
- "application/watcherinfo+xml": ["wif"],
1087
- "application/widget": ["wgt"],
1088
- "application/winhlp": ["hlp"],
1089
- "application/wsdl+xml": ["wsdl"],
1090
- "application/wspolicy+xml": ["wspolicy"],
1091
- "application/xaml+xml": ["xaml"],
1092
- "application/xcap-att+xml": ["xav"],
1093
- "application/xcap-caps+xml": ["xca"],
1094
- "application/xcap-diff+xml": ["xdf"],
1095
- "application/xcap-el+xml": ["xel"],
1096
- "application/xcap-ns+xml": ["xns"],
1097
- "application/xenc+xml": ["xenc"],
1098
- "application/xfdf": ["xfdf"],
1099
- "application/xhtml+xml": ["xhtml", "xht"],
1100
- "application/xliff+xml": ["xlf"],
1101
- "application/xml": [
1102
- "xml",
1103
- "xsl",
1104
- "xsd",
1105
- "rng"
1106
- ],
1107
- "application/xml-dtd": ["dtd"],
1108
- "application/xop+xml": ["xop"],
1109
- "application/xproc+xml": ["xpl"],
1110
- "application/xslt+xml": ["*xsl", "xslt"],
1111
- "application/xspf+xml": ["xspf"],
1112
- "application/xv+xml": [
1113
- "mxml",
1114
- "xhvml",
1115
- "xvml",
1116
- "xvm"
1117
- ],
1118
- "application/yang": ["yang"],
1119
- "application/yin+xml": ["yin"],
1120
- "application/zip": ["zip"],
1121
- "application/zip+dotlottie": ["lottie"],
1122
- "audio/3gpp": ["*3gpp"],
1123
- "audio/aac": ["adts", "aac"],
1124
- "audio/adpcm": ["adp"],
1125
- "audio/amr": ["amr"],
1126
- "audio/basic": ["au", "snd"],
1127
- "audio/midi": [
1128
- "mid",
1129
- "midi",
1130
- "kar",
1131
- "rmi"
1132
- ],
1133
- "audio/mobile-xmf": ["mxmf"],
1134
- "audio/mp3": ["*mp3"],
1135
- "audio/mp4": [
1136
- "m4a",
1137
- "mp4a",
1138
- "m4b"
1139
- ],
1140
- "audio/mpeg": [
1141
- "mpga",
1142
- "mp2",
1143
- "mp2a",
1144
- "mp3",
1145
- "m2a",
1146
- "m3a"
1147
- ],
1148
- "audio/ogg": [
1149
- "oga",
1150
- "ogg",
1151
- "spx",
1152
- "opus"
1153
- ],
1154
- "audio/s3m": ["s3m"],
1155
- "audio/silk": ["sil"],
1156
- "audio/wav": ["wav"],
1157
- "audio/wave": ["*wav"],
1158
- "audio/webm": ["weba"],
1159
- "audio/xm": ["xm"],
1160
- "font/collection": ["ttc"],
1161
- "font/otf": ["otf"],
1162
- "font/ttf": ["ttf"],
1163
- "font/woff": ["woff"],
1164
- "font/woff2": ["woff2"],
1165
- "image/aces": ["exr"],
1166
- "image/apng": ["apng"],
1167
- "image/avci": ["avci"],
1168
- "image/avcs": ["avcs"],
1169
- "image/avif": ["avif"],
1170
- "image/bmp": ["bmp", "dib"],
1171
- "image/cgm": ["cgm"],
1172
- "image/dicom-rle": ["drle"],
1173
- "image/dpx": ["dpx"],
1174
- "image/emf": ["emf"],
1175
- "image/fits": ["fits"],
1176
- "image/g3fax": ["g3"],
1177
- "image/gif": ["gif"],
1178
- "image/heic": ["heic"],
1179
- "image/heic-sequence": ["heics"],
1180
- "image/heif": ["heif"],
1181
- "image/heif-sequence": ["heifs"],
1182
- "image/hej2k": ["hej2"],
1183
- "image/ief": ["ief"],
1184
- "image/jaii": ["jaii"],
1185
- "image/jais": ["jais"],
1186
- "image/jls": ["jls"],
1187
- "image/jp2": ["jp2", "jpg2"],
1188
- "image/jpeg": [
1189
- "jpg",
1190
- "jpeg",
1191
- "jpe"
1192
- ],
1193
- "image/jph": ["jph"],
1194
- "image/jphc": ["jhc"],
1195
- "image/jpm": ["jpm", "jpgm"],
1196
- "image/jpx": ["jpx", "jpf"],
1197
- "image/jxl": ["jxl"],
1198
- "image/jxr": ["jxr"],
1199
- "image/jxra": ["jxra"],
1200
- "image/jxrs": ["jxrs"],
1201
- "image/jxs": ["jxs"],
1202
- "image/jxsc": ["jxsc"],
1203
- "image/jxsi": ["jxsi"],
1204
- "image/jxss": ["jxss"],
1205
- "image/ktx": ["ktx"],
1206
- "image/ktx2": ["ktx2"],
1207
- "image/pjpeg": ["jfif"],
1208
- "image/png": ["png"],
1209
- "image/sgi": ["sgi"],
1210
- "image/svg+xml": ["svg", "svgz"],
1211
- "image/t38": ["t38"],
1212
- "image/tiff": ["tif", "tiff"],
1213
- "image/tiff-fx": ["tfx"],
1214
- "image/webp": ["webp"],
1215
- "image/wmf": ["wmf"],
1216
- "message/disposition-notification": ["disposition-notification"],
1217
- "message/global": ["u8msg"],
1218
- "message/global-delivery-status": ["u8dsn"],
1219
- "message/global-disposition-notification": ["u8mdn"],
1220
- "message/global-headers": ["u8hdr"],
1221
- "message/rfc822": [
1222
- "eml",
1223
- "mime",
1224
- "mht",
1225
- "mhtml"
1226
- ],
1227
- "model/3mf": ["3mf"],
1228
- "model/gltf+json": ["gltf"],
1229
- "model/gltf-binary": ["glb"],
1230
- "model/iges": ["igs", "iges"],
1231
- "model/jt": ["jt"],
1232
- "model/mesh": [
1233
- "msh",
1234
- "mesh",
1235
- "silo"
1236
- ],
1237
- "model/mtl": ["mtl"],
1238
- "model/obj": ["obj"],
1239
- "model/prc": ["prc"],
1240
- "model/step": [
1241
- "step",
1242
- "stp",
1243
- "stpnc",
1244
- "p21",
1245
- "210"
1246
- ],
1247
- "model/step+xml": ["stpx"],
1248
- "model/step+zip": ["stpz"],
1249
- "model/step-xml+zip": ["stpxz"],
1250
- "model/stl": ["stl"],
1251
- "model/u3d": ["u3d"],
1252
- "model/vrml": ["wrl", "vrml"],
1253
- "model/x3d+binary": ["*x3db", "x3dbz"],
1254
- "model/x3d+fastinfoset": ["x3db"],
1255
- "model/x3d+vrml": ["*x3dv", "x3dvz"],
1256
- "model/x3d+xml": ["x3d", "x3dz"],
1257
- "model/x3d-vrml": ["x3dv"],
1258
- "text/cache-manifest": ["appcache", "manifest"],
1259
- "text/calendar": ["ics", "ifb"],
1260
- "text/coffeescript": ["coffee", "litcoffee"],
1261
- "text/css": ["css"],
1262
- "text/csv": ["csv"],
1263
- "text/html": [
1264
- "html",
1265
- "htm",
1266
- "shtml"
1267
- ],
1268
- "text/jade": ["jade"],
1269
- "text/javascript": ["js", "mjs"],
1270
- "text/jsx": ["jsx"],
1271
- "text/less": ["less"],
1272
- "text/markdown": ["md", "markdown"],
1273
- "text/mathml": ["mml"],
1274
- "text/mdx": ["mdx"],
1275
- "text/n3": ["n3"],
1276
- "text/plain": [
1277
- "txt",
1278
- "text",
1279
- "conf",
1280
- "def",
1281
- "list",
1282
- "log",
1283
- "in",
1284
- "ini"
1285
- ],
1286
- "text/richtext": ["rtx"],
1287
- "text/rtf": ["*rtf"],
1288
- "text/sgml": ["sgml", "sgm"],
1289
- "text/shex": ["shex"],
1290
- "text/slim": ["slim", "slm"],
1291
- "text/spdx": ["spdx"],
1292
- "text/stylus": ["stylus", "styl"],
1293
- "text/tab-separated-values": ["tsv"],
1294
- "text/troff": [
1295
- "t",
1296
- "tr",
1297
- "roff",
1298
- "man",
1299
- "me",
1300
- "ms"
1301
- ],
1302
- "text/turtle": ["ttl"],
1303
- "text/uri-list": [
1304
- "uri",
1305
- "uris",
1306
- "urls"
1307
- ],
1308
- "text/vcard": ["vcard"],
1309
- "text/vtt": ["vtt"],
1310
- "text/wgsl": ["wgsl"],
1311
- "text/xml": ["*xml"],
1312
- "text/yaml": ["yaml", "yml"],
1313
- "video/3gpp": ["3gp", "3gpp"],
1314
- "video/3gpp2": ["3g2"],
1315
- "video/h261": ["h261"],
1316
- "video/h263": ["h263"],
1317
- "video/h264": ["h264"],
1318
- "video/iso.segment": ["m4s"],
1319
- "video/jpeg": ["jpgv"],
1320
- "video/jpm": ["*jpm", "*jpgm"],
1321
- "video/mj2": ["mj2", "mjp2"],
1322
- "video/mp2t": [
1323
- "ts",
1324
- "m2t",
1325
- "m2ts",
1326
- "mts"
1327
- ],
1328
- "video/mp4": [
1329
- "mp4",
1330
- "mp4v",
1331
- "mpg4"
1332
- ],
1333
- "video/mpeg": [
1334
- "mpeg",
1335
- "mpg",
1336
- "mpe",
1337
- "m1v",
1338
- "m2v"
1339
- ],
1340
- "video/ogg": ["ogv"],
1341
- "video/quicktime": ["qt", "mov"],
1342
- "video/webm": ["webm"]
1343
- };
1344
- Object.freeze(types);
9
+ let _aws_sdk_client_s3 = require("@aws-sdk/client-s3");
10
+ let _aws_sdk_lib_storage = require("@aws-sdk/lib-storage");
11
+ //#region src/cloudFrontInvalidation.ts
12
+ const DEFAULT_POLL_INTERVAL_MS = 2e3;
13
+ const DEFAULT_TIMEOUT_MS = 300 * 1e3;
14
+ const sleep = (milliseconds) => new Promise((resolve) => setTimeout(resolve, milliseconds));
15
+ const invalidateCloudFront = async (client, distributionId, paths, options) => {
16
+ if (paths.length === 0) return;
17
+ const response = await client.send(new _aws_sdk_client_cloudfront.CreateInvalidationCommand({
18
+ DistributionId: distributionId,
19
+ InvalidationBatch: {
20
+ CallerReference: `invalidation-${Date.now()}`,
21
+ Paths: {
22
+ Quantity: paths.length,
23
+ Items: paths.map((path) => encodeURI(path))
24
+ }
25
+ }
26
+ }));
27
+ if (!options.shouldWait || response.Invalidation?.Status === "Completed") return;
28
+ const invalidationId = response.Invalidation?.Id;
29
+ if (!invalidationId) throw new Error("CloudFront invalidation response is missing Invalidation.Id");
30
+ const deadline = Date.now() + DEFAULT_TIMEOUT_MS;
31
+ while (Date.now() < deadline) {
32
+ await sleep(DEFAULT_POLL_INTERVAL_MS);
33
+ if ((await client.send(new _aws_sdk_client_cloudfront.GetInvalidationCommand({
34
+ DistributionId: distributionId,
35
+ Id: invalidationId
36
+ }))).Invalidation?.Status === "Completed") return;
37
+ }
38
+ throw new Error(`Timed out waiting for CloudFront invalidation ${invalidationId}.`);
39
+ };
1345
40
  //#endregion
1346
- //#region ../../node_modules/.pnpm/mime@4.1.0/node_modules/mime/dist/src/Mime.js
1347
- var __classPrivateFieldGet = function(receiver, state, kind, f) {
1348
- if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
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");
1350
- return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
1351
- };
1352
- var _Mime_extensionToType, _Mime_typeToExtension, _Mime_typeToExtensions;
1353
- var Mime = class {
1354
- constructor(...args) {
1355
- _Mime_extensionToType.set(this, /* @__PURE__ */ new Map());
1356
- _Mime_typeToExtension.set(this, /* @__PURE__ */ new Map());
1357
- _Mime_typeToExtensions.set(this, /* @__PURE__ */ new Map());
1358
- for (const arg of args) this.define(arg);
41
+ //#region src/dynamoDB.ts
42
+ const DYNAMODB_MAX_METADATA_ITEM_BYTES = 8 * 1024;
43
+ const DYNAMODB_MAX_CATALOG_ITEM_BYTES = 400 * 1024;
44
+ var DynamoDBMetadataItemSizeError = class extends Error {
45
+ name = "DynamoDBMetadataItemSizeError";
46
+ constructor(byteLength) {
47
+ super(`DynamoDB metadata item is ${byteLength} bytes; maximum is ${DYNAMODB_MAX_METADATA_ITEM_BYTES}`);
48
+ this.byteLength = byteLength;
49
+ }
50
+ };
51
+ const boundedDynamoDBMetadataItem = (item) => {
52
+ const byteLength = new TextEncoder().encode(JSON.stringify(item)).byteLength;
53
+ if (byteLength > 8192) throw new DynamoDBMetadataItemSizeError(byteLength);
54
+ return item;
55
+ };
56
+ var DynamoDBCatalogItemSizeError = class extends Error {
57
+ name = "DynamoDBCatalogItemSizeError";
58
+ constructor(byteLength) {
59
+ super(`DynamoDB catalog item is ${byteLength} bytes; maximum is ${DYNAMODB_MAX_CATALOG_ITEM_BYTES}`);
60
+ this.byteLength = byteLength;
61
+ }
62
+ };
63
+ const boundedDynamoDBCatalogItem = (item) => {
64
+ const byteLength = new TextEncoder().encode(JSON.stringify(item)).byteLength;
65
+ if (byteLength > 409600) throw new DynamoDBCatalogItemSizeError(byteLength);
66
+ return item;
67
+ };
68
+ const DYNAMODB_CHANNEL_PARTITION = "channels";
69
+ const DYNAMODB_CHANNEL_NAME_PARTITION = "_hot-updater#channel-names";
70
+ var DynamoDBStoredItemError = class extends Error {
71
+ name = "DynamoDBStoredItemError";
72
+ constructor() {
73
+ super("DynamoDB contains an invalid Hot Updater row");
74
+ }
75
+ };
76
+ const field = (value, name) => Reflect.get(value, name);
77
+ const isNullableString = (value) => value === null || typeof value === "string";
78
+ const isByteSize = (value) => typeof value === "number" && Number.isSafeInteger(value) && value >= 0;
79
+ const withLegacyArchiveByteSize = (value) => typeof value === "object" && value !== null && field(value, "archive_byte_size") === void 0 ? {
80
+ ...value,
81
+ archive_byte_size: 0
82
+ } : value;
83
+ const isBundleRow = (value) => typeof value === "object" && value !== null && typeof field(value, "id") === "string" && (field(value, "platform") === "ios" || field(value, "platform") === "android") && typeof field(value, "file_hash") === "string" && isNullableString(field(value, "git_commit_hash")) && typeof field(value, "storage_uri") === "string" && isByteSize(field(value, "archive_byte_size")) && (0, _hot_updater_plugin_core.isDatabaseMetadataObject)(field(value, "metadata")) && isNullableString(field(value, "manifest_storage_uri")) && isNullableString(field(value, "manifest_file_hash")) && isNullableString(field(value, "asset_base_storage_uri"));
84
+ const isPatchRow = (value) => typeof value === "object" && value !== null && typeof field(value, "id") === "string" && typeof field(value, "bundle_id") === "string" && typeof field(value, "base_bundle_id") === "string" && typeof field(value, "base_file_hash") === "string" && typeof field(value, "patch_file_hash") === "string" && typeof field(value, "patch_storage_uri") === "string" && isByteSize(field(value, "byte_size")) && typeof field(value, "order_index") === "number";
85
+ const isChannelRow = (value) => typeof value === "object" && value !== null && typeof field(value, "id") === "string" && typeof field(value, "name") === "string";
86
+ const isReleaseRow = (value) => typeof value === "object" && value !== null && typeof field(value, "id") === "string" && typeof field(value, "revision") === "number" && typeof field(value, "scope_key") === "string" && typeof field(value, "channel_id") === "string" && (field(value, "platform") === "ios" || field(value, "platform") === "android") && (field(value, "kind") === "BUNDLE" || field(value, "kind") === "EMBEDDED") && isNullableString(field(value, "bundle_id")) && (field(value, "strategy") === "APP_VERSION" || field(value, "strategy") === "FINGERPRINT") && isNullableString(field(value, "target_app_version")) && isNullableString(field(value, "fingerprint_hash")) && typeof field(value, "enabled") === "boolean" && typeof field(value, "should_force_update") === "boolean" && isNullableString(field(value, "message")) && typeof field(value, "rollout_cohort_count") === "number" && Array.isArray(field(value, "target_cohorts")) && field(value, "target_cohorts").every((cohort) => typeof cohort === "string") && (field(value, "operation") === "DEPLOY" || field(value, "operation") === "PROMOTE" || field(value, "operation") === "ROLLBACK") && isNullableString(field(value, "source_release_id")) && typeof field(value, "created_at_ms") === "number" && typeof field(value, "updated_at_ms") === "number";
87
+ const isReleaseCatalogRow = (value) => typeof value === "object" && value !== null && typeof field(value, "scope_key") === "string" && typeof field(value, "catalog_id") === "string" && (field(value, "strategy") === "APP_VERSION" || field(value, "strategy") === "FINGERPRINT") && typeof field(value, "channel_id") === "string" && typeof field(value, "channel_key") === "string" && (field(value, "platform") === "ios" || field(value, "platform") === "android") && isNullableString(field(value, "fingerprint_hash")) && typeof field(value, "generation") === "number" && typeof field(value, "payload") === "string" && typeof field(value, "catalog_hash") === "string" && typeof field(value, "byte_size") === "number" && typeof field(value, "is_tombstone") === "boolean" && typeof field(value, "updated_at_ms") === "number";
88
+ const parseDynamoDBItem = (value) => {
89
+ const pk = value.pk;
90
+ const sk = value.sk;
91
+ const version = value.version;
92
+ const relationCount = value.relation_count;
93
+ const ownedPatchCount = value.owned_patch_count;
94
+ const gsi1pk = value.gsi1pk;
95
+ const gsi1sk = value.gsi1sk;
96
+ const row = pk === "bundles" ? withLegacyArchiveByteSize(value.row) : value.row;
97
+ if (typeof sk !== "string" || typeof version !== "number") throw new DynamoDBStoredItemError();
98
+ if (pk === "channels" && typeof value.reference_count === "number" && isChannelRow(row)) return {
99
+ pk,
100
+ sk,
101
+ version,
102
+ reference_count: value.reference_count,
103
+ row
104
+ };
105
+ if (typeof pk === "string" && pk.startsWith("release-scope#") && isReleaseRow(row)) return {
106
+ pk,
107
+ sk,
108
+ version,
109
+ row
110
+ };
111
+ if (pk === "release_catalogs" && isReleaseCatalogRow(row)) return {
112
+ pk,
113
+ sk,
114
+ version,
115
+ row
116
+ };
117
+ if (typeof gsi1pk !== "string" || typeof gsi1sk !== "string") throw new DynamoDBStoredItemError();
118
+ if (pk === "bundles" && isBundleRow(row)) {
119
+ if (typeof relationCount !== "number" || typeof ownedPatchCount !== "number") throw new DynamoDBStoredItemError();
120
+ return {
121
+ pk,
122
+ sk,
123
+ version,
124
+ relation_count: relationCount,
125
+ owned_patch_count: ownedPatchCount,
126
+ gsi1pk,
127
+ gsi1sk,
128
+ row
129
+ };
130
+ }
131
+ if (pk === "bundle_patches" && isPatchRow(row)) return {
132
+ pk,
133
+ sk,
134
+ version,
135
+ gsi1pk,
136
+ gsi1sk,
137
+ row
138
+ };
139
+ throw new DynamoDBStoredItemError();
140
+ };
141
+ const bundlePlatformPartition = (row) => `bundle#${row.platform}`;
142
+ const patchOwnerPartition = (bundleId) => `patch-owner#${bundleId}`;
143
+ const patchOrderKey = (row) => `${row.order_index.toString().padStart(10, "0")}#${row.id}`;
144
+ const toDynamoDBBundleItem = (row, version = 1, relationCount = 0, ownedPatchCount = 0) => ({
145
+ pk: "bundles",
146
+ sk: row.id,
147
+ version,
148
+ relation_count: relationCount,
149
+ owned_patch_count: ownedPatchCount,
150
+ gsi1pk: bundlePlatformPartition(row),
151
+ gsi1sk: row.id,
152
+ row
153
+ });
154
+ const toDynamoDBPatchItem = (row, version = 1) => {
155
+ const orderKey = patchOrderKey(row);
156
+ return {
157
+ pk: "bundle_patches",
158
+ sk: row.id,
159
+ version,
160
+ gsi1pk: patchOwnerPartition(row.bundle_id),
161
+ gsi1sk: orderKey,
162
+ row
163
+ };
164
+ };
165
+ const toDynamoDBChannelItem = (row, version = 1, referenceCount = 0) => ({
166
+ pk: DYNAMODB_CHANNEL_PARTITION,
167
+ sk: row.id,
168
+ version,
169
+ reference_count: referenceCount,
170
+ row
171
+ });
172
+ const releaseScopePartition = (scopeKey) => `release-scope#${scopeKey}`;
173
+ const toDynamoDBReleaseItem = (row, version = 1) => ({
174
+ pk: releaseScopePartition(row.scope_key),
175
+ sk: row.id,
176
+ version,
177
+ row
178
+ });
179
+ const toDynamoDBReleaseCatalogItem = (row, version = 1) => ({
180
+ pk: "release_catalogs",
181
+ sk: row.scope_key,
182
+ version,
183
+ row
184
+ });
185
+ const itemKey = (model, id) => ({
186
+ pk: model,
187
+ sk: id
188
+ });
189
+ const exactDynamoDBId = (where) => {
190
+ if (where?.length !== 1) return void 0;
191
+ const condition = where[0];
192
+ if (Reflect.get(condition, "field") !== "id" || (Reflect.get(condition, "operator") ?? "eq") !== "eq" || Reflect.get(condition, "mode") === "insensitive") return;
193
+ const value = Reflect.get(condition, "value");
194
+ return typeof value === "string" ? value : void 0;
195
+ };
196
+ const exactDynamoDBPatchOwner = (where) => {
197
+ const owners = exactDynamoDBPatchOwners(where);
198
+ return owners?.length === 1 ? owners[0] : void 0;
199
+ };
200
+ const exactDynamoDBPatchOwners = (where) => {
201
+ if (!where || where.some((condition) => Reflect.get(condition, "connector") === "OR")) return;
202
+ const ownerConditions = where.filter((condition) => Reflect.get(condition, "field") === "bundle_id");
203
+ if (ownerConditions.length !== 1) return void 0;
204
+ const condition = ownerConditions[0];
205
+ if (Reflect.get(condition, "mode") === "insensitive") return;
206
+ const operator = Reflect.get(condition, "operator") ?? "eq";
207
+ const value = Reflect.get(condition, "value");
208
+ if (operator === "eq") return typeof value === "string" ? [value] : void 0;
209
+ if (operator === "in" && Array.isArray(value) && value.every((id) => typeof id === "string")) return value;
210
+ };
211
+ const exactDynamoDBBundleIds = (where) => {
212
+ if (!where || where.some((condition) => Reflect.get(condition, "connector") === "OR")) return;
213
+ for (const condition of where) {
214
+ if (Reflect.get(condition, "field") !== "id" || Reflect.get(condition, "mode") === "insensitive") continue;
215
+ const operator = Reflect.get(condition, "operator") ?? "eq";
216
+ const value = Reflect.get(condition, "value");
217
+ if (operator === "eq" && typeof value === "string") return [value];
218
+ if (operator === "in" && Array.isArray(value) && value.every((id) => typeof id === "string")) return value;
219
+ }
220
+ };
221
+ const dynamoDBBundlePageStart = (where, direction) => {
222
+ if ((where ?? []).some((condition) => Reflect.get(condition, "connector") === "OR")) return;
223
+ let result;
224
+ for (const condition of where ?? []) {
225
+ if (Reflect.get(condition, "field") !== "id") continue;
226
+ const operator = Reflect.get(condition, "operator") ?? "eq";
227
+ const value = Reflect.get(condition, "value");
228
+ if (!(direction === "asc" ? operator === "gt" || operator === "gte" : operator === "lt" || operator === "lte") || typeof value !== "string") continue;
229
+ const inclusive = operator === "gte" || operator === "lte";
230
+ if (result === void 0 || (direction === "asc" ? value > result.id : value < result.id) || value === result.id && !inclusive) result = {
231
+ id: value,
232
+ inclusive
233
+ };
1359
234
  }
1360
- define(typeMap, force = false) {
1361
- for (let [type, extensions] of Object.entries(typeMap)) {
1362
- type = type.toLowerCase();
1363
- extensions = extensions.map((ext) => ext.toLowerCase());
1364
- if (!__classPrivateFieldGet(this, _Mime_typeToExtensions, "f").has(type)) __classPrivateFieldGet(this, _Mime_typeToExtensions, "f").set(type, /* @__PURE__ */ new Set());
1365
- const allExtensions = __classPrivateFieldGet(this, _Mime_typeToExtensions, "f").get(type);
1366
- let first = true;
1367
- for (let extension of extensions) {
1368
- const starred = extension.startsWith("*");
1369
- extension = starred ? extension.slice(1) : extension;
1370
- allExtensions?.add(extension);
1371
- if (first) __classPrivateFieldGet(this, _Mime_typeToExtension, "f").set(type, extension);
1372
- first = false;
1373
- if (starred) continue;
1374
- const currentType = __classPrivateFieldGet(this, _Mime_extensionToType, "f").get(extension);
1375
- if (currentType && currentType != type && !force) throw new Error(`"${type} -> ${extension}" conflicts with "${currentType} -> ${extension}". Pass \`force=true\` to override this definition.`);
1376
- __classPrivateFieldGet(this, _Mime_extensionToType, "f").set(extension, type);
235
+ return result;
236
+ };
237
+ const parseStoredItem = (item) => parseDynamoDBItem(item.pk === "release_catalogs" ? boundedDynamoDBCatalogItem(item) : boundedDynamoDBMetadataItem(item));
238
+ const queryItems = async (store, input) => {
239
+ let exclusiveStartKey;
240
+ const items = [];
241
+ do {
242
+ const sortCondition = input.minimumSortKey ? " AND #sortKey >= :minimumSortKey" : "";
243
+ const page = await store.client.send(new _aws_sdk_lib_dynamodb.QueryCommand({
244
+ TableName: store.tableName,
245
+ ...input.indexName ? { IndexName: input.indexName } : {},
246
+ ...input.consistentRead ? { ConsistentRead: true } : {},
247
+ ExclusiveStartKey: exclusiveStartKey,
248
+ KeyConditionExpression: `#partitionKey = :partition${sortCondition}`,
249
+ ExpressionAttributeNames: {
250
+ "#partitionKey": input.indexName ? "gsi1pk" : "pk",
251
+ ...input.minimumSortKey ? { "#sortKey": input.indexName ? "gsi1sk" : "sk" } : {}
252
+ },
253
+ ExpressionAttributeValues: {
254
+ ":partition": input.partition,
255
+ ...input.minimumSortKey ? { ":minimumSortKey": input.minimumSortKey } : {}
1377
256
  }
257
+ }));
258
+ const pageItems = (page.Items ?? []).map(parseStoredItem);
259
+ items.push(...pageItems);
260
+ exclusiveStartKey = page.LastEvaluatedKey;
261
+ } while (exclusiveStartKey !== void 0);
262
+ return items;
263
+ };
264
+ const queryBundleItemsPage = async (store, input) => {
265
+ if (input.limit === 0) return [];
266
+ let exclusiveStartKey;
267
+ const items = [];
268
+ do {
269
+ const startOperator = input.start?.inclusive ? input.direction === "asc" ? ">=" : "<=" : input.direction === "asc" ? ">" : "<";
270
+ const page = await store.client.send(new _aws_sdk_lib_dynamodb.QueryCommand({
271
+ TableName: store.tableName,
272
+ ExclusiveStartKey: exclusiveStartKey,
273
+ KeyConditionExpression: input.start ? `#pk = :pk AND #sk ${startOperator} :start` : "#pk = :pk",
274
+ ExpressionAttributeNames: {
275
+ "#pk": "pk",
276
+ ...input.start ? { "#sk": "sk" } : {}
277
+ },
278
+ ExpressionAttributeValues: {
279
+ ":pk": "bundles",
280
+ ...input.start ? { ":start": input.start.id } : {}
281
+ },
282
+ Limit: Math.max(input.limit - items.length, 100),
283
+ ScanIndexForward: input.direction === "asc"
284
+ }));
285
+ for (const item of (page.Items ?? []).map(parseStoredItem)) {
286
+ if (item.pk === "bundles" && input.matches(item.row)) items.push(item);
287
+ if (items.length === input.limit) return items;
288
+ }
289
+ exclusiveStartKey = page.LastEvaluatedKey;
290
+ } while (exclusiveStartKey !== void 0);
291
+ return items;
292
+ };
293
+ const loadModelItems = (store, model) => queryItems(store, {
294
+ partition: model,
295
+ consistentRead: true
296
+ });
297
+ const loadModelItem = async (store, model, id) => {
298
+ const { Item } = await store.client.send(new _aws_sdk_lib_dynamodb.GetCommand({
299
+ TableName: store.tableName,
300
+ Key: itemKey(model, id),
301
+ ConsistentRead: true
302
+ }));
303
+ return Item === void 0 ? void 0 : parseStoredItem(Item);
304
+ };
305
+ const loadBundleItem = async (store, id) => {
306
+ const item = await loadModelItem(store, "bundles", id);
307
+ return item?.pk === "bundles" ? item : void 0;
308
+ };
309
+ const loadPatchItem = async (store, id) => {
310
+ const item = await loadModelItem(store, "bundle_patches", id);
311
+ return item?.pk === "bundle_patches" ? item : void 0;
312
+ };
313
+ const loadChannelItem = async (store, id) => {
314
+ const item = await loadModelItem(store, DYNAMODB_CHANNEL_PARTITION, id);
315
+ return item?.pk === "channels" ? item : void 0;
316
+ };
317
+ const loadBundleItems = async (store) => {
318
+ return (await loadModelItems(store, "bundles")).filter((item) => item.pk === "bundles");
319
+ };
320
+ const loadPatchItems = async (store) => {
321
+ return (await loadModelItems(store, "bundle_patches")).filter((item) => item.pk === "bundle_patches");
322
+ };
323
+ const loadChannelItems = async (store) => {
324
+ return (await loadModelItems(store, DYNAMODB_CHANNEL_PARTITION)).filter((item) => item.pk === DYNAMODB_CHANNEL_PARTITION);
325
+ };
326
+ const DYNAMODB_RELEASE_ID_PARTITION = "_hot-updater#release-scope-by-id";
327
+ const releaseLocatorItem = (row) => ({
328
+ pk: DYNAMODB_RELEASE_ID_PARTITION,
329
+ sk: row.id,
330
+ scope_key: row.scope_key
331
+ });
332
+ const loadReleaseItem = async (store, id) => {
333
+ const locator = await store.client.send(new _aws_sdk_lib_dynamodb.GetCommand({
334
+ TableName: store.tableName,
335
+ Key: {
336
+ pk: DYNAMODB_RELEASE_ID_PARTITION,
337
+ sk: id
338
+ },
339
+ ConsistentRead: true
340
+ }));
341
+ if (locator.Item === void 0) return void 0;
342
+ const scopeKey = locator.Item.scope_key;
343
+ if (typeof scopeKey !== "string") throw new DynamoDBStoredItemError();
344
+ const result = await store.client.send(new _aws_sdk_lib_dynamodb.GetCommand({
345
+ TableName: store.tableName,
346
+ Key: {
347
+ pk: releaseScopePartition(scopeKey),
348
+ sk: id
349
+ },
350
+ ConsistentRead: true
351
+ }));
352
+ if (result.Item === void 0) throw new DynamoDBStoredItemError();
353
+ const item = parseStoredItem(result.Item);
354
+ if (!isReleaseRow(item.row) || item.sk !== id) throw new DynamoDBStoredItemError();
355
+ return item;
356
+ };
357
+ const loadReleaseItemsByScope = async (store, scopeKey) => (await queryItems(store, {
358
+ partition: releaseScopePartition(scopeKey),
359
+ consistentRead: true
360
+ })).filter((item) => item.pk === releaseScopePartition(scopeKey) && isReleaseRow(item.row));
361
+ const loadReleaseItems = async (store) => {
362
+ let exclusiveStartKey;
363
+ const items = [];
364
+ do {
365
+ const page = await store.client.send(new _aws_sdk_lib_dynamodb.ScanCommand({
366
+ TableName: store.tableName,
367
+ ExclusiveStartKey: exclusiveStartKey,
368
+ ConsistentRead: true,
369
+ FilterExpression: "begins_with(#pk, :prefix)",
370
+ ExpressionAttributeNames: { "#pk": "pk" },
371
+ ExpressionAttributeValues: { ":prefix": "release-scope#" }
372
+ }));
373
+ for (const value of page.Items ?? []) {
374
+ const item = parseStoredItem(value);
375
+ if (isReleaseRow(item.row)) items.push(item);
1378
376
  }
1379
- return this;
377
+ exclusiveStartKey = page.LastEvaluatedKey;
378
+ } while (exclusiveStartKey !== void 0);
379
+ return items;
380
+ };
381
+ const loadReleaseCatalogItem = async (store, scopeKey) => {
382
+ const result = await store.client.send(new _aws_sdk_lib_dynamodb.GetCommand({
383
+ TableName: store.tableName,
384
+ Key: itemKey("release_catalogs", scopeKey),
385
+ ConsistentRead: true
386
+ }));
387
+ if (result.Item === void 0) return void 0;
388
+ const item = parseStoredItem(result.Item);
389
+ return item.pk === "release_catalogs" ? item : void 0;
390
+ };
391
+ const loadReleaseCatalogItems = async (store) => (await queryItems(store, {
392
+ partition: "release_catalogs",
393
+ consistentRead: true
394
+ })).filter((item) => item.pk === "release_catalogs");
395
+ const loadChannelByName = async (store, name) => {
396
+ const { Item } = await store.client.send(new _aws_sdk_lib_dynamodb.GetCommand({
397
+ TableName: store.tableName,
398
+ Key: {
399
+ pk: DYNAMODB_CHANNEL_NAME_PARTITION,
400
+ sk: name
401
+ },
402
+ ConsistentRead: true
403
+ }));
404
+ const id = Item?.channel_id;
405
+ if (Item === void 0) return void 0;
406
+ if (typeof id !== "string") throw new DynamoDBStoredItemError();
407
+ const channel = await loadChannelItem(store, id);
408
+ if (channel === void 0 || channel.row.name !== name) throw new DynamoDBStoredItemError();
409
+ return channel;
410
+ };
411
+ const insertDynamoDBChannel = async (store, input) => {
412
+ const existing = await loadChannelByName(store, input.row.name);
413
+ if (existing !== void 0) return {
414
+ row: existing.row,
415
+ inserted: false
416
+ };
417
+ const existingId = await loadChannelItem(store, input.row.id);
418
+ if (existingId !== void 0) {
419
+ if (existingId.row.name === input.row.name) return {
420
+ row: existingId.row,
421
+ inserted: false
422
+ };
423
+ throw new DynamoDBStoredItemError();
1380
424
  }
1381
- getType(path) {
1382
- if (typeof path !== "string") return null;
1383
- const last = path.replace(/^.*[/\\]/s, "").toLowerCase();
1384
- const ext = last.replace(/^.*\./s, "").toLowerCase();
1385
- const hasPath = last.length < path.length;
1386
- if (!(ext.length < last.length - 1) && hasPath) return null;
1387
- return __classPrivateFieldGet(this, _Mime_extensionToType, "f").get(ext) ?? null;
425
+ try {
426
+ await commitDynamoDBTransaction(store, [{ Put: {
427
+ TableName: store.tableName,
428
+ Item: boundedDynamoDBMetadataItem(toDynamoDBChannelItem(input.row)),
429
+ ConditionExpression: "attribute_not_exists(#pk)",
430
+ ExpressionAttributeNames: { "#pk": "pk" }
431
+ } }, { Put: {
432
+ TableName: store.tableName,
433
+ Item: {
434
+ pk: DYNAMODB_CHANNEL_NAME_PARTITION,
435
+ sk: input.row.name,
436
+ channel_id: input.row.id
437
+ },
438
+ ConditionExpression: "attribute_not_exists(#pk)",
439
+ ExpressionAttributeNames: { "#pk": "pk" }
440
+ } }]);
441
+ return {
442
+ row: input.row,
443
+ inserted: true
444
+ };
445
+ } catch (error) {
446
+ const canonical = await loadChannelByName(store, input.row.name);
447
+ if (canonical !== void 0) return {
448
+ row: canonical.row,
449
+ inserted: false
450
+ };
451
+ throw error;
1388
452
  }
1389
- getExtension(type) {
1390
- if (typeof type !== "string") return null;
1391
- type = type?.split?.(";")[0];
1392
- return (type && __classPrivateFieldGet(this, _Mime_typeToExtension, "f").get(type.trim().toLowerCase())) ?? null;
453
+ };
454
+ const deleteDynamoDBChannel = async (store, input) => {
455
+ const current = await loadChannelItem(store, input.id);
456
+ if (current === void 0) return {
457
+ deleted: false,
458
+ reason: "not_found"
459
+ };
460
+ if (current.reference_count !== 0) return {
461
+ deleted: false,
462
+ reason: "not_empty"
463
+ };
464
+ try {
465
+ await commitDynamoDBTransaction(store, [{ Delete: {
466
+ TableName: store.tableName,
467
+ Key: itemKey(DYNAMODB_CHANNEL_PARTITION, current.sk),
468
+ ConditionExpression: "#version = :version AND #referenceCount = :zero",
469
+ ExpressionAttributeNames: {
470
+ "#version": "version",
471
+ "#referenceCount": "reference_count"
472
+ },
473
+ ExpressionAttributeValues: {
474
+ ":version": current.version,
475
+ ":zero": 0
476
+ }
477
+ } }, { Delete: {
478
+ TableName: store.tableName,
479
+ Key: {
480
+ pk: DYNAMODB_CHANNEL_NAME_PARTITION,
481
+ sk: current.row.name
482
+ },
483
+ ConditionExpression: "#channelId = :channelId",
484
+ ExpressionAttributeNames: { "#channelId": "channel_id" },
485
+ ExpressionAttributeValues: { ":channelId": current.sk }
486
+ } }]);
487
+ return { deleted: true };
488
+ } catch (error) {
489
+ const latest = await loadChannelItem(store, input.id);
490
+ if (latest !== void 0 && latest.reference_count > 0) return {
491
+ deleted: false,
492
+ reason: "not_empty"
493
+ };
494
+ if (latest === void 0) return {
495
+ deleted: false,
496
+ reason: "not_found"
497
+ };
498
+ throw error;
499
+ }
500
+ };
501
+ const queryOwnerPatchIds = async (store, indexName, bundleId) => {
502
+ return (await queryItems(store, {
503
+ partition: patchOwnerPartition(bundleId),
504
+ indexName
505
+ })).filter((item) => item.pk === "bundle_patches").map(({ sk }) => sk);
506
+ };
507
+ var DynamoDBTransactionLimitError = class extends Error {
508
+ name = "DynamoDBTransactionLimitError";
509
+ constructor(actionCount) {
510
+ super(`DynamoDB transaction requires ${actionCount} actions; maximum is 100`);
511
+ this.actionCount = actionCount;
512
+ }
513
+ };
514
+ const metadataUpdate = (store, delta) => {
515
+ const entries = Object.entries(delta).filter(([, value]) => value !== 0);
516
+ if (entries.length === 0) return void 0;
517
+ const names = {};
518
+ const values = {};
519
+ const updates = [];
520
+ const conditions = [];
521
+ for (const [model, change] of entries) {
522
+ const name = model === "bundles" ? "bundles" : "patches";
523
+ const valueName = model === "bundles" ? "bundle" : "patch";
524
+ names[`#${name}`] = name;
525
+ values[`:${valueName}Delta`] = change;
526
+ updates.push(`#${name} :${valueName}Delta`);
527
+ if (change < 0) {
528
+ values[`:${valueName}Removal`] = -change;
529
+ conditions.push(`#${name} >= :${valueName}Removal`);
530
+ }
531
+ }
532
+ return { Update: {
533
+ TableName: store.tableName,
534
+ Key: {
535
+ pk: "_hot-updater",
536
+ sk: "limits.metadata"
537
+ },
538
+ UpdateExpression: `ADD ${updates.join(", ")}`,
539
+ ...conditions.length > 0 ? { ConditionExpression: conditions.join(" AND ") } : {},
540
+ ExpressionAttributeNames: names,
541
+ ExpressionAttributeValues: values
542
+ } };
543
+ };
544
+ const updateBundleRelation = (store, bundleId, delta, ownedPatchDelta = 0) => {
545
+ const names = {
546
+ "#pk": "pk",
547
+ "#version": "version"
548
+ };
549
+ const values = { ":one": 1 };
550
+ const additions = [];
551
+ let condition = "attribute_exists(#pk)";
552
+ let update = "SET #version = #version + :one";
553
+ if (delta !== 0) {
554
+ names["#relationCount"] = "relation_count";
555
+ values[":relationDelta"] = delta;
556
+ additions.push("#relationCount :relationDelta");
557
+ if (delta < 0) {
558
+ values[":relationRemoval"] = -delta;
559
+ condition += " AND #relationCount >= :relationRemoval";
560
+ }
561
+ }
562
+ if (ownedPatchDelta !== 0) {
563
+ names["#ownedPatchCount"] = "owned_patch_count";
564
+ values[":ownedPatchDelta"] = ownedPatchDelta;
565
+ additions.push("#ownedPatchCount :ownedPatchDelta");
566
+ if (ownedPatchDelta < 0) {
567
+ values[":ownedPatchRemoval"] = -ownedPatchDelta;
568
+ condition += " AND #ownedPatchCount >= :ownedPatchRemoval";
569
+ }
570
+ }
571
+ if (additions.length > 0) update += ` ADD ${additions.join(", ")}`;
572
+ return { Update: {
573
+ TableName: store.tableName,
574
+ Key: itemKey("bundles", bundleId),
575
+ ConditionExpression: condition,
576
+ ExpressionAttributeNames: names,
577
+ ExpressionAttributeValues: values,
578
+ UpdateExpression: update
579
+ } };
580
+ };
581
+ const commitDynamoDBTransaction = async (store, actions) => {
582
+ if (actions.length > 100) throw new DynamoDBTransactionLimitError(actions.length);
583
+ await store.client.send(new _aws_sdk_lib_dynamodb.TransactWriteCommand({ TransactItems: [...actions] }));
584
+ };
585
+ const DYNAMODB_BATCH_GET_ATTEMPTS = 5;
586
+ const DYNAMODB_BATCH_GET_BASE_DELAY_MS = 25;
587
+ var DynamoDBBatchGetExhaustedError = class extends Error {
588
+ name = "DynamoDBBatchGetExhaustedError";
589
+ constructor(unprocessedKeyCount) {
590
+ super(`DynamoDB did not process ${unprocessedKeyCount} batch-get keys after ${DYNAMODB_BATCH_GET_ATTEMPTS} attempts`);
591
+ this.unprocessedKeyCount = unprocessedKeyCount;
592
+ }
593
+ };
594
+ const waitBeforeRetry = (attempt) => new Promise((resolve) => setTimeout(resolve, DYNAMODB_BATCH_GET_BASE_DELAY_MS * 2 ** attempt));
595
+ const batchGetDynamoDBItems = async (store, keys) => {
596
+ const items = [];
597
+ for (let offset = 0; offset < keys.length; offset += 100) {
598
+ let pending = keys.slice(offset, offset + 100);
599
+ for (let attempt = 0; attempt < DYNAMODB_BATCH_GET_ATTEMPTS && pending.length > 0; attempt++) {
600
+ const { Responses, UnprocessedKeys } = await store.client.send(new _aws_sdk_lib_dynamodb.BatchGetCommand({ RequestItems: { [store.tableName]: {
601
+ ConsistentRead: true,
602
+ Keys: pending
603
+ } } }));
604
+ items.push(...Responses?.[store.tableName] ?? []);
605
+ pending = UnprocessedKeys?.[store.tableName]?.Keys ?? [];
606
+ if (pending.length > 0 && attempt + 1 < DYNAMODB_BATCH_GET_ATTEMPTS) await waitBeforeRetry(attempt);
607
+ }
608
+ if (pending.length > 0) throw new DynamoDBBatchGetExhaustedError(pending.length);
609
+ }
610
+ return items;
611
+ };
612
+ const parseKeyReadItem = (item) => parseDynamoDBItem(boundedDynamoDBMetadataItem(item));
613
+ const loadBundleItemsById = async (store, ids) => {
614
+ const uniqueIds = [...new Set(ids)];
615
+ if (uniqueIds.length === 0) return [];
616
+ return (await batchGetDynamoDBItems(store, uniqueIds.map((id) => itemKey("bundles", id)))).map(parseKeyReadItem).filter((item) => item.pk === "bundles");
617
+ };
618
+ const loadPatchItemsById = async (store, ids) => {
619
+ const uniqueIds = [...new Set(ids)];
620
+ if (uniqueIds.length === 0) return [];
621
+ return (await batchGetDynamoDBItems(store, uniqueIds.map((id) => itemKey("bundle_patches", id)))).map(parseKeyReadItem).filter((item) => item.pk === "bundle_patches");
622
+ };
623
+ const loadMetadataCount = async (store, model) => {
624
+ if (model !== "bundles" && model !== "bundle_patches") return void 0;
625
+ const field = model === "bundles" ? "bundles" : "patches";
626
+ const { Item } = await store.client.send(new _aws_sdk_lib_dynamodb.GetCommand({
627
+ TableName: store.tableName,
628
+ Key: {
629
+ pk: "_hot-updater",
630
+ sk: "limits.metadata"
631
+ },
632
+ ConsistentRead: true,
633
+ ProjectionExpression: "#count",
634
+ ExpressionAttributeNames: { "#count": field }
635
+ }));
636
+ const count = Item?.[field];
637
+ return typeof count === "number" && Number.isSafeInteger(count) && count >= 0 ? count : void 0;
638
+ };
639
+ var DynamoDBPatchIndexConsistencyError = class extends Error {
640
+ name = "DynamoDBPatchIndexConsistencyError";
641
+ constructor(bundleId, expectedCount) {
642
+ super(`DynamoDB patch index did not converge to ${expectedCount} rows for bundle "${bundleId}"`);
643
+ this.bundleId = bundleId;
644
+ this.expectedCount = expectedCount;
645
+ }
646
+ };
647
+ const waitForIndex = (attempt) => new Promise((resolve) => setTimeout(resolve, 20 * (attempt + 1)));
648
+ const queryCompleteOwnerPatches = async (store, indexName, bundleId) => {
649
+ const owner = await loadBundleItem(store, bundleId);
650
+ if (!owner || owner.owned_patch_count === 0) return [];
651
+ for (let attempt = 0; attempt < 3; attempt++) {
652
+ const patchIds = await queryOwnerPatchIds(store, indexName, bundleId);
653
+ const patchIdSet = new Set(patchIds);
654
+ const patches = (await loadPatchItemsById(store, patchIds)).filter(({ row }) => row.bundle_id === bundleId);
655
+ if (patchIds.length === owner.owned_patch_count && patchIdSet.size === owner.owned_patch_count && patches.length === owner.owned_patch_count && patches.every(({ sk }) => patchIdSet.has(sk))) return patches.map(({ row }) => row).sort((left, right) => left.order_index - right.order_index || left.id.localeCompare(right.id));
656
+ if (attempt < 2) await waitForIndex(attempt);
1393
657
  }
1394
- getAllExtensions(type) {
1395
- if (typeof type !== "string") return null;
1396
- return __classPrivateFieldGet(this, _Mime_typeToExtensions, "f").get(type.toLowerCase()) ?? null;
658
+ throw new DynamoDBPatchIndexConsistencyError(bundleId, owner.owned_patch_count);
659
+ };
660
+ const queryCompleteOwnersPatches = async (store, indexName, bundleIds) => {
661
+ const owners = (await loadBundleItemsById(store, bundleIds)).filter(({ owned_patch_count }) => owned_patch_count > 0);
662
+ const firstOwner = owners[0];
663
+ if (!firstOwner) return [];
664
+ let failedOwner = firstOwner;
665
+ for (let attempt = 0; attempt < 3; attempt++) {
666
+ const candidateIdsByOwner = await Promise.all(owners.map(({ sk }) => queryOwnerPatchIds(store, indexName, sk)));
667
+ const patches = await loadPatchItemsById(store, candidateIdsByOwner.flat());
668
+ const patchesById = new Map(patches.map((patch) => [patch.sk, patch]));
669
+ const mismatchedOwner = owners.find((owner, ownerIndex) => {
670
+ const ids = candidateIdsByOwner[ownerIndex] ?? [];
671
+ const uniqueIds = new Set(ids);
672
+ return ids.length !== owner.owned_patch_count || uniqueIds.size !== owner.owned_patch_count || ids.some((id) => patchesById.get(id)?.row.bundle_id !== owner.sk);
673
+ });
674
+ if (!mismatchedOwner) return patches.map(({ row }) => row);
675
+ failedOwner = mismatchedOwner;
676
+ if (attempt < 2) await waitForIndex(attempt);
677
+ }
678
+ throw new DynamoDBPatchIndexConsistencyError(failedOwner.sk, failedOwner.owned_patch_count);
679
+ };
680
+ const createDynamoDBBundlePatchTable = (store, indexName) => ({ findByBundleIds: (bundleIds) => bundleIds.length === 0 ? Promise.resolve([]) : queryCompleteOwnersPatches(store, indexName, bundleIds) });
681
+ const compare = (left, right) => {
682
+ if (typeof left === "number" && typeof right === "number") return left - right;
683
+ if (left == null) return right == null ? 0 : -1;
684
+ if (right == null) return 1;
685
+ return JSON.stringify(left).localeCompare(JSON.stringify(right));
686
+ };
687
+ const compareString = (actual, expected, mode, predicate) => {
688
+ if (typeof actual !== "string") return false;
689
+ return mode === "insensitive" ? predicate(actual.toLocaleLowerCase(), expected.toLocaleLowerCase()) : predicate(actual, expected);
690
+ };
691
+ const matchesCondition = (row, condition) => {
692
+ const actual = Reflect.get(row, condition.field);
693
+ const expected = Reflect.get(condition, "value");
694
+ switch (Reflect.get(condition, "operator") ?? "eq") {
695
+ case "eq": return typeof expected === "string" ? compareString(actual, expected, Reflect.get(condition, "mode"), (value, query) => value === query) : actual === expected;
696
+ case "ne":
697
+ if (actual == null) return false;
698
+ return typeof expected === "string" ? !compareString(actual, expected, Reflect.get(condition, "mode"), (value, query) => value === query) : actual !== expected;
699
+ case "gt": return actual != null && compare(actual, expected) > 0;
700
+ case "gte": return actual != null && compare(actual, expected) >= 0;
701
+ case "lt": return actual != null && compare(actual, expected) < 0;
702
+ case "lte": return actual != null && compare(actual, expected) <= 0;
703
+ case "in": return Array.isArray(expected) && expected.some((candidate) => candidate === actual);
704
+ case "not_in": return Array.isArray(expected) && (expected.length === 0 || actual != null && expected.every((candidate) => candidate !== actual));
705
+ case "contains": return typeof expected === "string" ? compareString(actual, expected, Reflect.get(condition, "mode"), (value, query) => value.includes(query)) : false;
706
+ case "starts_with": return typeof expected === "string" ? compareString(actual, expected, Reflect.get(condition, "mode"), (value, query) => value.startsWith(query)) : false;
707
+ case "ends_with": return typeof expected === "string" ? compareString(actual, expected, Reflect.get(condition, "mode"), (value, query) => value.endsWith(query)) : false;
708
+ default: return false;
1397
709
  }
1398
- _freeze() {
1399
- this.define = () => {
1400
- throw new Error("define() not allowed for built-in Mime objects. See https://github.com/broofa/mime/blob/main/README.md#custom-mime-instances");
710
+ };
711
+ const matchesDynamoDBWhere = (row, where) => {
712
+ if (!where || where.length === 0) return true;
713
+ let result = matchesCondition(row, where[0]);
714
+ for (const condition of where.slice(1)) {
715
+ const current = matchesCondition(row, condition);
716
+ result = condition.connector === "OR" ? result || current : result && current;
717
+ }
718
+ return result;
719
+ };
720
+ const compareRows = (left, right, orderBy) => {
721
+ for (const clause of orderBy) {
722
+ const leftValue = Reflect.get(left, clause.field);
723
+ const rightValue = Reflect.get(right, clause.field);
724
+ if (leftValue == null || rightValue == null) {
725
+ if (leftValue == null && rightValue == null) continue;
726
+ const nulls = clause.nulls ?? (clause.direction === "asc" ? "last" : "first");
727
+ const order = leftValue == null ? -1 : 1;
728
+ return nulls === "first" ? order : -order;
729
+ }
730
+ const order = compare(leftValue, rightValue);
731
+ if (order !== 0) return clause.direction === "asc" ? order : -order;
732
+ }
733
+ return 0;
734
+ };
735
+ const distinctKey = (row, distinctOn) => JSON.stringify(distinctOn.fields.map((field) => Reflect.get(row, field)));
736
+ const queryDynamoDBRows = (rows, input) => {
737
+ const filtered = rows.filter((row) => matchesDynamoDBWhere(row, input.where));
738
+ const orderBy = input.orderBy;
739
+ const ordered = orderBy ? filtered.toSorted((left, right) => compareRows(left, right, orderBy)) : filtered;
740
+ const distinctOn = input.distinctOn;
741
+ const distinct = distinctOn ? (() => {
742
+ const seen = /* @__PURE__ */ new Set();
743
+ return ordered.filter((row) => {
744
+ const key = distinctKey(row, distinctOn);
745
+ if (seen.has(key)) return false;
746
+ seen.add(key);
747
+ return true;
748
+ });
749
+ })() : ordered;
750
+ const offset = input.offset ?? 0;
751
+ return distinct.slice(offset, offset + (input.limit ?? 100));
752
+ };
753
+ const countDistinctDynamoDBRows = (rows, fields) => {
754
+ if (fields === void 0) return rows.length;
755
+ return new Set(rows.map((row) => JSON.stringify(fields.map((field) => Reflect.get(row, field))))).size;
756
+ };
757
+ const createDynamoDBBundle = async (store, row) => {
758
+ const counter = metadataUpdate(store, { bundles: 1 });
759
+ if (!counter) return;
760
+ await commitDynamoDBTransaction(store, [counter, { Put: {
761
+ TableName: store.tableName,
762
+ Item: boundedDynamoDBMetadataItem(toDynamoDBBundleItem(row)),
763
+ ConditionExpression: "attribute_not_exists(#pk)",
764
+ ExpressionAttributeNames: { "#pk": "pk" }
765
+ } }]);
766
+ };
767
+ const createDynamoDBPatch = async (store, row) => {
768
+ const bundleIds = [...new Set([row.bundle_id, row.base_bundle_id])];
769
+ const counter = metadataUpdate(store, { bundle_patches: 1 });
770
+ if (!counter) return;
771
+ await commitDynamoDBTransaction(store, [
772
+ counter,
773
+ ...bundleIds.map((bundleId) => updateBundleRelation(store, bundleId, 1, bundleId === row.bundle_id ? 1 : 0)),
774
+ { Put: {
775
+ TableName: store.tableName,
776
+ Item: boundedDynamoDBMetadataItem(toDynamoDBPatchItem(row)),
777
+ ConditionExpression: "attribute_not_exists(#pk)",
778
+ ExpressionAttributeNames: { "#pk": "pk" }
779
+ } }
780
+ ]);
781
+ };
782
+ const replaceDynamoDBBundle = async (store, current, row) => {
783
+ await store.client.send(new _aws_sdk_lib_dynamodb.PutCommand({
784
+ TableName: store.tableName,
785
+ Item: boundedDynamoDBMetadataItem(toDynamoDBBundleItem(row, current.version + 1, current.relation_count, current.owned_patch_count)),
786
+ ConditionExpression: "#version = :currentVersion",
787
+ ExpressionAttributeNames: { "#version": "version" },
788
+ ExpressionAttributeValues: { ":currentVersion": current.version }
789
+ }));
790
+ };
791
+ const deleteAction = (store, item) => ({ Delete: {
792
+ TableName: store.tableName,
793
+ Key: {
794
+ pk: item.pk,
795
+ sk: item.sk
796
+ },
797
+ ConditionExpression: "#version = :currentVersion",
798
+ ExpressionAttributeNames: { "#version": "version" },
799
+ ExpressionAttributeValues: { ":currentVersion": item.version }
800
+ } });
801
+ const deleteDynamoDBPatch = async (store, item) => {
802
+ const counter = metadataUpdate(store, { bundle_patches: -1 });
803
+ if (!counter) return;
804
+ await commitDynamoDBTransaction(store, [
805
+ counter,
806
+ ...[...new Set([item.row.bundle_id, item.row.base_bundle_id])].map((id) => updateBundleRelation(store, id, -1, id === item.row.bundle_id ? -1 : 0)),
807
+ deleteAction(store, item)
808
+ ]);
809
+ };
810
+ const deleteBundle = async (store, bundle, patches) => {
811
+ const counter = metadataUpdate(store, {
812
+ bundles: -1,
813
+ bundle_patches: -patches.length
814
+ });
815
+ if (!counter) return;
816
+ const otherEndpointCounts = /* @__PURE__ */ new Map();
817
+ for (const { row } of patches) for (const id of new Set([row.bundle_id, row.base_bundle_id])) {
818
+ if (id === bundle.sk) continue;
819
+ const current = otherEndpointCounts.get(id) ?? {
820
+ owned: 0,
821
+ relations: 0
1401
822
  };
1402
- Object.freeze(this);
1403
- for (const extensions of __classPrivateFieldGet(this, _Mime_typeToExtensions, "f").values()) Object.freeze(extensions);
1404
- return this;
823
+ otherEndpointCounts.set(id, {
824
+ owned: current.owned + (id === row.bundle_id ? 1 : 0),
825
+ relations: current.relations + 1
826
+ });
1405
827
  }
1406
- _getTestState() {
1407
- return {
1408
- types: __classPrivateFieldGet(this, _Mime_extensionToType, "f"),
1409
- extensions: __classPrivateFieldGet(this, _Mime_typeToExtension, "f")
828
+ await commitDynamoDBTransaction(store, [
829
+ counter,
830
+ ...[...otherEndpointCounts].map(([id, count]) => updateBundleRelation(store, id, -count.relations, -count.owned)),
831
+ ...patches.map((patch) => deleteAction(store, patch)),
832
+ deleteAction(store, bundle)
833
+ ]);
834
+ };
835
+ const deleteDynamoDBBundles = async (store, bundles, allPatches) => {
836
+ let patches = [...allPatches];
837
+ const versionIncrements = /* @__PURE__ */ new Map();
838
+ for (const originalBundle of bundles) {
839
+ const bundle = {
840
+ ...originalBundle,
841
+ version: originalBundle.version + (versionIncrements.get(originalBundle.sk) ?? 0)
1410
842
  };
843
+ const related = patches.filter(({ row }) => row.bundle_id === bundle.sk || row.base_bundle_id === bundle.sk);
844
+ await deleteBundle(store, bundle, related);
845
+ const updatedBundleIds = new Set(related.flatMap(({ row }) => [row.bundle_id, row.base_bundle_id]));
846
+ updatedBundleIds.delete(bundle.sk);
847
+ for (const id of updatedBundleIds) versionIncrements.set(id, (versionIncrements.get(id) ?? 0) + 1);
848
+ const removedPatchIds = new Set(related.map(({ sk }) => sk));
849
+ patches = patches.filter(({ sk }) => !removedPatchIds.has(sk));
1411
850
  }
1412
851
  };
1413
- _Mime_extensionToType = /* @__PURE__ */ new WeakMap(), _Mime_typeToExtension = /* @__PURE__ */ new WeakMap(), _Mime_typeToExtensions = /* @__PURE__ */ new WeakMap();
1414
- //#endregion
1415
- //#region ../../node_modules/.pnpm/mime@4.1.0/node_modules/mime/dist/src/index.js
1416
- var src_default = new Mime(types, types$1)._freeze();
852
+ var DynamoDBUnsupportedModelError = class extends Error {
853
+ name = "DynamoDBUnsupportedModelError";
854
+ constructor() {
855
+ super("DynamoDB received an unsupported database model");
856
+ }
857
+ };
858
+ const distinctFields = (fields) => fields;
859
+ const exactDynamoDBField = (where, fieldName) => {
860
+ const conditions = (where ?? []).filter((condition) => Reflect.get(condition, "field") === fieldName);
861
+ if (conditions.length !== 1) return void 0;
862
+ const condition = conditions[0];
863
+ if ((Reflect.get(condition, "operator") ?? "eq") !== "eq" || Reflect.get(condition, "mode") === "insensitive") return;
864
+ const value = Reflect.get(condition, "value");
865
+ return typeof value === "string" ? value : void 0;
866
+ };
867
+ const createDynamoDBCrud = (store, updateIndexName) => ({
868
+ async create(input) {
869
+ switch (input.model) {
870
+ case "bundles":
871
+ await createDynamoDBBundle(store, input.data);
872
+ return input.data;
873
+ case "bundle_patches":
874
+ await createDynamoDBPatch(store, input.data);
875
+ return input.data;
876
+ case "releases": {
877
+ const channel = await loadChannelItem(store, input.data.channel_id);
878
+ if (channel === void 0) throw new DynamoDBStoredItemError();
879
+ await commitDynamoDBTransaction(store, [
880
+ updateChannelReferenceCount(store, channel, 1),
881
+ { Put: {
882
+ TableName: store.tableName,
883
+ Item: boundedDynamoDBMetadataItem(toDynamoDBReleaseItem(input.data)),
884
+ ConditionExpression: "attribute_not_exists(#pk)",
885
+ ExpressionAttributeNames: { "#pk": "pk" }
886
+ } },
887
+ { Put: {
888
+ TableName: store.tableName,
889
+ Item: releaseLocatorItem(input.data),
890
+ ConditionExpression: "attribute_not_exists(#pk)",
891
+ ExpressionAttributeNames: { "#pk": "pk" }
892
+ } }
893
+ ]);
894
+ return input.data;
895
+ }
896
+ case "release_catalogs":
897
+ await store.client.send(new _aws_sdk_lib_dynamodb.PutCommand({
898
+ TableName: store.tableName,
899
+ Item: boundedDynamoDBCatalogItem(toDynamoDBReleaseCatalogItem(input.data)),
900
+ ConditionExpression: "attribute_not_exists(#pk)",
901
+ ExpressionAttributeNames: { "#pk": "pk" }
902
+ }));
903
+ return input.data;
904
+ case "channels": return (await insertDynamoDBChannel(store, {
905
+ row: input.data,
906
+ onConflict: "returnExisting"
907
+ })).row;
908
+ }
909
+ throw new DynamoDBUnsupportedModelError();
910
+ },
911
+ async update(input) {
912
+ if (input.model === "releases") {
913
+ const id = exactDynamoDBId(input.where);
914
+ if (id === void 0) throw new DynamoDBUnsupportedModelError();
915
+ const current = await loadReleaseItem(store, id);
916
+ if (current === void 0) return null;
917
+ const updated = {
918
+ ...current.row,
919
+ ...input.update
920
+ };
921
+ const nextPartition = releaseScopePartition(updated.scope_key);
922
+ const moved = current.pk !== nextPartition;
923
+ await commitDynamoDBTransaction(store, [
924
+ ...moved ? [{ Delete: {
925
+ TableName: store.tableName,
926
+ Key: {
927
+ pk: current.pk,
928
+ sk: current.sk
929
+ },
930
+ ConditionExpression: "#version = :version",
931
+ ExpressionAttributeNames: { "#version": "version" },
932
+ ExpressionAttributeValues: { ":version": current.version }
933
+ } }] : [],
934
+ { Put: {
935
+ TableName: store.tableName,
936
+ Item: boundedDynamoDBMetadataItem(toDynamoDBReleaseItem(updated, current.version + 1)),
937
+ ConditionExpression: moved ? "attribute_not_exists(#pk)" : "#version = :version",
938
+ ExpressionAttributeNames: moved ? { "#pk": "pk" } : { "#version": "version" },
939
+ ...moved ? {} : { ExpressionAttributeValues: { ":version": current.version } }
940
+ } },
941
+ { Put: {
942
+ TableName: store.tableName,
943
+ Item: releaseLocatorItem(updated),
944
+ ConditionExpression: "#scopeKey = :scopeKey",
945
+ ExpressionAttributeNames: { "#scopeKey": "scope_key" },
946
+ ExpressionAttributeValues: { ":scopeKey": current.row.scope_key }
947
+ } }
948
+ ]);
949
+ return updated;
950
+ }
951
+ if (input.model === "release_catalogs") {
952
+ const scopeKey = exactDynamoDBField(input.where, "scope_key");
953
+ if (scopeKey === void 0) throw new DynamoDBUnsupportedModelError();
954
+ const current = await loadReleaseCatalogItem(store, scopeKey);
955
+ if (current === void 0) return null;
956
+ const updated = {
957
+ ...current.row,
958
+ ...input.update
959
+ };
960
+ await store.client.send(new _aws_sdk_lib_dynamodb.PutCommand({
961
+ TableName: store.tableName,
962
+ Item: boundedDynamoDBCatalogItem(toDynamoDBReleaseCatalogItem(updated, current.version + 1)),
963
+ ConditionExpression: "#version = :version",
964
+ ExpressionAttributeNames: { "#version": "version" },
965
+ ExpressionAttributeValues: { ":version": current.version }
966
+ }));
967
+ return updated;
968
+ }
969
+ if (input.model !== "bundles") throw new DynamoDBUnsupportedModelError();
970
+ const id = exactDynamoDBId(input.where);
971
+ const current = id === void 0 ? (await loadBundleItems(store)).find(({ row }) => matchesDynamoDBWhere(row, input.where)) : await loadBundleItem(store, id);
972
+ if (!current) return null;
973
+ const updated = {
974
+ ...current.row,
975
+ ...input.update
976
+ };
977
+ await replaceDynamoDBBundle(store, current, updated);
978
+ return updated;
979
+ },
980
+ async delete(input) {
981
+ if (input.model === "channels") {
982
+ const id = exactDynamoDBId(input.where);
983
+ if (id !== void 0) await deleteDynamoDBChannel(store, { id });
984
+ return;
985
+ }
986
+ if (input.model === "bundle_patches") {
987
+ const items = (await loadPatchItems(store)).filter(({ row }) => matchesDynamoDBWhere(row, input.where));
988
+ for (const item of items) await deleteDynamoDBPatch(store, item);
989
+ return;
990
+ }
991
+ if (input.model === "releases") {
992
+ const items = (await loadReleaseItems(store)).filter(({ row }) => matchesDynamoDBWhere(row, input.where));
993
+ for (const item of items) {
994
+ const channel = await loadChannelItem(store, item.row.channel_id);
995
+ if (channel === void 0) throw new DynamoDBStoredItemError();
996
+ await commitDynamoDBTransaction(store, [
997
+ updateChannelReferenceCount(store, channel, -1),
998
+ deleteAction(store, item),
999
+ { Delete: {
1000
+ TableName: store.tableName,
1001
+ Key: {
1002
+ pk: DYNAMODB_RELEASE_ID_PARTITION,
1003
+ sk: item.sk
1004
+ },
1005
+ ConditionExpression: "#scopeKey = :scopeKey",
1006
+ ExpressionAttributeNames: { "#scopeKey": "scope_key" },
1007
+ ExpressionAttributeValues: { ":scopeKey": item.row.scope_key }
1008
+ } }
1009
+ ]);
1010
+ }
1011
+ return;
1012
+ }
1013
+ if (input.model !== "bundles") throw new DynamoDBUnsupportedModelError();
1014
+ const bundleItems = (await loadBundleItems(store)).filter(({ row }) => matchesDynamoDBWhere(row, input.where));
1015
+ if (bundleItems.length === 0) return;
1016
+ await deleteDynamoDBBundles(store, bundleItems, await loadPatchItems(store));
1017
+ },
1018
+ async count(input) {
1019
+ if ((input.where === void 0 || input.where.length === 0) && input.distinct === void 0) {
1020
+ const count = await loadMetadataCount(store, input.model);
1021
+ if (count !== void 0) return count;
1022
+ }
1023
+ switch (input.model) {
1024
+ case "bundles": return countDistinctDynamoDBRows((await loadBundleItems(store)).map(({ row }) => row).filter((row) => matchesDynamoDBWhere(row, input.where)), distinctFields(input.distinct));
1025
+ case "bundle_patches": {
1026
+ const ownerId = exactDynamoDBPatchOwner(input.where);
1027
+ return countDistinctDynamoDBRows((ownerId ? await queryCompleteOwnerPatches(store, updateIndexName, ownerId) : (await loadPatchItems(store)).map(({ row }) => row)).filter((row) => matchesDynamoDBWhere(row, input.where)), distinctFields(input.distinct));
1028
+ }
1029
+ case "releases": {
1030
+ const scopeKey = exactDynamoDBField(input.where, "scope_key");
1031
+ return countDistinctDynamoDBRows((scopeKey === void 0 ? await loadReleaseItems(store) : await loadReleaseItemsByScope(store, scopeKey)).map(({ row }) => row).filter((row) => matchesDynamoDBWhere(row, input.where)), distinctFields(input.distinct));
1032
+ }
1033
+ }
1034
+ throw new DynamoDBUnsupportedModelError();
1035
+ },
1036
+ async findOne(input) {
1037
+ const id = exactDynamoDBId(input.where);
1038
+ switch (input.model) {
1039
+ case "bundles":
1040
+ if (id !== void 0) return (await loadBundleItem(store, id))?.row ?? null;
1041
+ return (await loadBundleItems(store)).map(({ row }) => row).find((row) => matchesDynamoDBWhere(row, input.where)) ?? null;
1042
+ case "bundle_patches":
1043
+ if (id !== void 0) return (await loadPatchItem(store, id))?.row ?? null;
1044
+ {
1045
+ const ownerId = exactDynamoDBPatchOwner(input.where);
1046
+ if (ownerId === void 0) break;
1047
+ return (await queryCompleteOwnerPatches(store, updateIndexName, ownerId)).find((row) => matchesDynamoDBWhere(row, input.where)) ?? null;
1048
+ }
1049
+ break;
1050
+ case "channels":
1051
+ if (id !== void 0) return (await loadChannelItem(store, id))?.row ?? null;
1052
+ return (await loadChannelItems(store)).map(({ row }) => row).find((row) => matchesDynamoDBWhere(row, input.where)) ?? null;
1053
+ case "releases":
1054
+ if (id !== void 0) return (await loadReleaseItem(store, id))?.row ?? null;
1055
+ {
1056
+ const scopeKey = exactDynamoDBField(input.where, "scope_key");
1057
+ return (scopeKey === void 0 ? await loadReleaseItems(store) : await loadReleaseItemsByScope(store, scopeKey)).map(({ row }) => row).find((row) => matchesDynamoDBWhere(row, input.where)) ?? null;
1058
+ }
1059
+ case "release_catalogs": {
1060
+ const scopeKey = exactDynamoDBField(input.where, "scope_key");
1061
+ if (scopeKey !== void 0) return (await loadReleaseCatalogItem(store, scopeKey))?.row ?? null;
1062
+ return (await loadReleaseCatalogItems(store)).map(({ row }) => row).find((row) => matchesDynamoDBWhere(row, input.where)) ?? null;
1063
+ }
1064
+ }
1065
+ if (input.model === "bundle_patches") return (await loadPatchItems(store)).map(({ row }) => row).find((row) => matchesDynamoDBWhere(row, input.where)) ?? null;
1066
+ throw new DynamoDBUnsupportedModelError();
1067
+ },
1068
+ async findMany(input) {
1069
+ if (input.limit === 0) return [];
1070
+ switch (input.model) {
1071
+ case "bundles": {
1072
+ const ids = exactDynamoDBBundleIds(input.where);
1073
+ if (ids !== void 0) return queryDynamoDBRows((await loadBundleItemsById(store, ids)).map(({ row }) => row), input);
1074
+ const orderBy = input.orderBy;
1075
+ const direction = orderBy?.[0]?.direction;
1076
+ if ((input.offset ?? 0) === 0 && input.distinctOn === void 0 && orderBy?.length === 1 && orderBy[0]?.field === "id" && (direction === "asc" || direction === "desc")) return (await queryBundleItemsPage(store, {
1077
+ direction,
1078
+ limit: input.limit ?? 100,
1079
+ matches: (row) => matchesDynamoDBWhere(row, input.where),
1080
+ start: dynamoDBBundlePageStart(input.where, direction)
1081
+ })).map(({ row }) => row);
1082
+ return queryDynamoDBRows((await loadBundleItems(store)).map(({ row }) => row), input);
1083
+ }
1084
+ case "bundle_patches": {
1085
+ const ownerIds = exactDynamoDBPatchOwners(input.where);
1086
+ if (ownerIds !== void 0) {
1087
+ const ownerId = ownerIds.length === 1 ? ownerIds[0] : void 0;
1088
+ return queryDynamoDBRows(ownerId !== void 0 ? await queryCompleteOwnerPatches(store, updateIndexName, ownerId) : await queryCompleteOwnersPatches(store, updateIndexName, ownerIds), input);
1089
+ }
1090
+ return queryDynamoDBRows((await loadPatchItems(store)).map(({ row }) => row), input);
1091
+ }
1092
+ case "channels": return queryDynamoDBRows((await loadChannelItems(store)).map(({ row }) => row), input);
1093
+ case "releases": {
1094
+ const scopeKey = exactDynamoDBField(input.where, "scope_key");
1095
+ return queryDynamoDBRows((scopeKey === void 0 ? await loadReleaseItems(store) : await loadReleaseItemsByScope(store, scopeKey)).map(({ row }) => row), input);
1096
+ }
1097
+ case "release_catalogs": return queryDynamoDBRows((await loadReleaseCatalogItems(store)).map(({ row }) => row), input);
1098
+ }
1099
+ throw new DynamoDBUnsupportedModelError();
1100
+ },
1101
+ insertChannel: (input) => insertDynamoDBChannel(store, input),
1102
+ deleteChannel: (input) => deleteDynamoDBChannel(store, input)
1103
+ });
1104
+ var DynamoDBDuplicatePatchError = class extends Error {
1105
+ name = "DynamoDBDuplicatePatchError";
1106
+ constructor(patchId) {
1107
+ super(`DynamoDB bundle mutation contains duplicate patch "${patchId}"`);
1108
+ this.patchId = patchId;
1109
+ }
1110
+ };
1111
+ const putNewBundle = (store, row, relationCount, ownedPatchCount = relationCount) => ({ Put: {
1112
+ TableName: store.tableName,
1113
+ Item: boundedDynamoDBMetadataItem(toDynamoDBBundleItem(row, 1, relationCount, ownedPatchCount)),
1114
+ ConditionExpression: "attribute_not_exists(#pk)",
1115
+ ExpressionAttributeNames: { "#pk": "pk" }
1116
+ } });
1117
+ const putUpdatedBundle = (store, current, row, relationCount, ownedPatchCount) => ({ Put: {
1118
+ TableName: store.tableName,
1119
+ Item: boundedDynamoDBMetadataItem(toDynamoDBBundleItem(row, current.version + 1, relationCount, ownedPatchCount)),
1120
+ ConditionExpression: "#version = :currentVersion",
1121
+ ExpressionAttributeNames: { "#version": "version" },
1122
+ ExpressionAttributeValues: { ":currentVersion": current.version }
1123
+ } });
1124
+ const putPatch = (store, row, current) => ({ Put: {
1125
+ TableName: store.tableName,
1126
+ Item: boundedDynamoDBMetadataItem(toDynamoDBPatchItem(row, (current?.version ?? 0) + 1)),
1127
+ ConditionExpression: current ? "#version = :currentVersion" : "attribute_not_exists(#pk)",
1128
+ ExpressionAttributeNames: current ? { "#version": "version" } : { "#pk": "pk" },
1129
+ ...current ? { ExpressionAttributeValues: { ":currentVersion": current.version } } : {}
1130
+ } });
1131
+ const deletePatch = (store, item) => ({ Delete: {
1132
+ TableName: store.tableName,
1133
+ Key: itemKey(item.pk, item.sk),
1134
+ ConditionExpression: "#version = :currentVersion",
1135
+ ExpressionAttributeNames: { "#version": "version" },
1136
+ ExpressionAttributeValues: { ":currentVersion": item.version }
1137
+ } });
1138
+ var DynamoDBCommitStateError = class extends Error {
1139
+ name = "DynamoDBCommitStateError";
1140
+ constructor(message) {
1141
+ super(message);
1142
+ }
1143
+ };
1144
+ const rowsEqual = (left, right) => JSON.stringify(left) === JSON.stringify(right);
1145
+ const putChannel = (store, row, current, referenceCount) => ({ Put: {
1146
+ TableName: store.tableName,
1147
+ Item: boundedDynamoDBMetadataItem(toDynamoDBChannelItem(row, (current?.version ?? 0) + 1, referenceCount)),
1148
+ ConditionExpression: current ? "#version = :version" : "attribute_not_exists(#pk)",
1149
+ ExpressionAttributeNames: current ? { "#version": "version" } : { "#pk": "pk" },
1150
+ ...current ? { ExpressionAttributeValues: { ":version": current.version } } : {}
1151
+ } });
1152
+ const deleteChannelActions = (store, current) => [{ Delete: {
1153
+ TableName: store.tableName,
1154
+ Key: itemKey(DYNAMODB_CHANNEL_PARTITION, current.sk),
1155
+ ConditionExpression: "#version = :version",
1156
+ ExpressionAttributeNames: { "#version": "version" },
1157
+ ExpressionAttributeValues: { ":version": current.version }
1158
+ } }, { Delete: {
1159
+ TableName: store.tableName,
1160
+ Key: {
1161
+ pk: DYNAMODB_CHANNEL_NAME_PARTITION,
1162
+ sk: current.row.name
1163
+ },
1164
+ ConditionExpression: "#channelId = :channelId",
1165
+ ExpressionAttributeNames: { "#channelId": "channel_id" },
1166
+ ExpressionAttributeValues: { ":channelId": current.sk }
1167
+ } }];
1168
+ const updateChannelReferenceCount = (store, current, delta) => ({ Update: {
1169
+ TableName: store.tableName,
1170
+ Key: itemKey(DYNAMODB_CHANNEL_PARTITION, current.sk),
1171
+ ConditionExpression: "#row.#name = :name" + (delta < 0 ? " AND #referenceCount >= :removal" : ""),
1172
+ UpdateExpression: "SET #version = #version + :one ADD #referenceCount :delta",
1173
+ ExpressionAttributeNames: {
1174
+ "#row": "row",
1175
+ "#name": "name",
1176
+ "#version": "version",
1177
+ "#referenceCount": "reference_count"
1178
+ },
1179
+ ExpressionAttributeValues: {
1180
+ ":name": current.row.name,
1181
+ ":one": 1,
1182
+ ":delta": delta,
1183
+ ...delta < 0 ? { ":removal": -delta } : {}
1184
+ }
1185
+ } });
1186
+ const loadApiKeyByHash = async (store, hash) => {
1187
+ const { Item } = await store.client.send(new _aws_sdk_lib_dynamodb.GetCommand({
1188
+ TableName: store.tableName,
1189
+ Key: {
1190
+ pk: DYNAMODB_API_KEY_HASH_PARTITION,
1191
+ sk: hash
1192
+ },
1193
+ ConsistentRead: true
1194
+ }));
1195
+ if (Item === void 0) return null;
1196
+ const id = Item.api_key_id;
1197
+ if (typeof id !== "string") throw new DynamoDBStoredItemError();
1198
+ return loadApiKey(store, id);
1199
+ };
1200
+ const compileAndCommitDynamoDBChanges = async (store, input) => {
1201
+ const [originalBundleItems, originalPatchItems, originalChannelItems, originalReleaseItems, originalReleaseCatalogItems] = await Promise.all([
1202
+ loadBundleItems(store),
1203
+ loadPatchItems(store),
1204
+ loadChannelItems(store),
1205
+ loadReleaseItems(store),
1206
+ loadReleaseCatalogItems(store)
1207
+ ]);
1208
+ const bundles = new Map(originalBundleItems.map(({ sk, row }) => [sk, row]));
1209
+ const patches = new Map(originalPatchItems.map(({ sk, row }) => [sk, row]));
1210
+ const channels = new Map(originalChannelItems.map(({ sk, row }) => [sk, row]));
1211
+ const channelNames = new Map(originalChannelItems.map(({ sk, row }) => [row.name, sk]));
1212
+ const releases = new Map(originalReleaseItems.map(({ sk, row }) => [sk, row]));
1213
+ const releaseCatalogs = new Map(originalReleaseCatalogItems.map(({ sk, row }) => [sk, row]));
1214
+ const originalApiKeys = /* @__PURE__ */ new Map();
1215
+ const apiKeys = /* @__PURE__ */ new Map();
1216
+ const apiKeyHashes = /* @__PURE__ */ new Map();
1217
+ const analytics = /* @__PURE__ */ new Map();
1218
+ const rememberApiKey = (value) => {
1219
+ if (value === null || apiKeys.has(value.row.id)) return;
1220
+ originalApiKeys.set(value.row.id, value);
1221
+ apiKeys.set(value.row.id, value);
1222
+ apiKeyHashes.set(value.row.hash, value.row.id);
1223
+ };
1224
+ const requireReleaseReferences = (row) => {
1225
+ if (!channels.has(row.channel_id)) throw new DynamoDBCommitStateError(`Release "${row.id}" references an invalid channel`);
1226
+ if (row.bundle_id !== null) {
1227
+ const bundle = bundles.get(row.bundle_id);
1228
+ if (bundle === void 0 || bundle.platform !== row.platform) throw new DynamoDBCommitStateError(`Release "${row.id}" references an invalid bundle`);
1229
+ }
1230
+ };
1231
+ for (const expectation of input.expectations ?? []) {
1232
+ const actualVersion = expectation.model === "releases" ? releases.get(expectation.id)?.revision ?? null : releaseCatalogs.get(expectation.scopeKey)?.generation ?? null;
1233
+ const expectedVersion = expectation.model === "releases" ? expectation.revision : expectation.generation;
1234
+ if (actualVersion !== expectedVersion) return {
1235
+ committed: false,
1236
+ conflict: {
1237
+ actualVersion,
1238
+ changeIndex: -1,
1239
+ expectedVersion,
1240
+ key: expectation.model === "releases" ? expectation.id : expectation.scopeKey,
1241
+ model: expectation.model,
1242
+ reason: "version_conflict"
1243
+ }
1244
+ };
1245
+ }
1246
+ for (const [changeIndex, change] of input.changes.entries()) switch (change.model) {
1247
+ case "channels":
1248
+ if (change.operation === "insert") {
1249
+ if (channelNames.get(change.row.name) !== void 0) break;
1250
+ if (channels.get(change.row.id) !== void 0) throw new DynamoDBCommitStateError(`Channel id "${change.row.id}" already exists`);
1251
+ channels.set(change.row.id, change.row);
1252
+ channelNames.set(change.row.name, change.row.id);
1253
+ } else {
1254
+ const current = channels.get(change.where.id);
1255
+ if (current === void 0) break;
1256
+ if ([...releases.values()].some(({ channel_id }) => channel_id === change.where.id)) return {
1257
+ committed: false,
1258
+ conflict: {
1259
+ changeIndex,
1260
+ reason: "referenced"
1261
+ }
1262
+ };
1263
+ channels.delete(change.where.id);
1264
+ channelNames.delete(current.name);
1265
+ }
1266
+ break;
1267
+ case "bundles":
1268
+ if (change.operation === "insert") {
1269
+ if (bundles.has(change.row.id)) throw new DynamoDBCommitStateError(`Bundle "${change.row.id}" already exists`);
1270
+ bundles.set(change.row.id, change.row);
1271
+ } else {
1272
+ const current = bundles.get(change.where.id);
1273
+ if (current === void 0) {
1274
+ if (change.operation === "update") return {
1275
+ committed: false,
1276
+ conflict: {
1277
+ changeIndex,
1278
+ reason: "not_found"
1279
+ }
1280
+ };
1281
+ break;
1282
+ }
1283
+ if (change.operation === "update") {
1284
+ const row = {
1285
+ ...current,
1286
+ ...change.update
1287
+ };
1288
+ bundles.set(row.id, row);
1289
+ } else {
1290
+ if ([...releases.values()].some(({ bundle_id }) => bundle_id === change.where.id)) return {
1291
+ committed: false,
1292
+ conflict: {
1293
+ changeIndex,
1294
+ reason: "referenced"
1295
+ }
1296
+ };
1297
+ bundles.delete(change.where.id);
1298
+ for (const [id, patch] of patches) if (patch.bundle_id === change.where.id || patch.base_bundle_id === change.where.id) patches.delete(id);
1299
+ }
1300
+ }
1301
+ break;
1302
+ case "releases":
1303
+ if (change.operation === "insert") {
1304
+ requireReleaseReferences(change.row);
1305
+ if (releases.has(change.row.id)) throw new DynamoDBCommitStateError(`Release "${change.row.id}" already exists`);
1306
+ releases.set(change.row.id, change.row);
1307
+ } else {
1308
+ const current = releases.get(change.where.id);
1309
+ if (current === void 0) {
1310
+ if (change.operation === "update") return {
1311
+ committed: false,
1312
+ conflict: {
1313
+ changeIndex,
1314
+ reason: "not_found"
1315
+ }
1316
+ };
1317
+ break;
1318
+ }
1319
+ if (change.operation === "update") {
1320
+ const row = {
1321
+ ...current,
1322
+ ...change.update
1323
+ };
1324
+ requireReleaseReferences(row);
1325
+ releases.set(row.id, row);
1326
+ } else releases.delete(change.where.id);
1327
+ }
1328
+ break;
1329
+ case "releaseCatalogs":
1330
+ if (!channels.has(change.row.channel_id)) throw new DynamoDBCommitStateError(`Release catalog "${change.row.scope_key}" references an invalid channel`);
1331
+ releaseCatalogs.set(change.row.scope_key, change.row);
1332
+ break;
1333
+ case "bundlePatches":
1334
+ if (change.operation === "insert") {
1335
+ if (!bundles.has(change.row.bundle_id) || !bundles.has(change.row.base_bundle_id)) throw new DynamoDBCommitStateError(`Patch "${change.row.id}" references a missing bundle`);
1336
+ if (patches.has(change.row.id)) throw new DynamoDBDuplicatePatchError(change.row.id);
1337
+ patches.set(change.row.id, change.row);
1338
+ } else for (const [id, patch] of patches) if (patch.bundle_id === change.where.bundleId) patches.delete(id);
1339
+ break;
1340
+ case "analytics": {
1341
+ const key = analyticsSortKey(change.row);
1342
+ if (analytics.has(key)) throw new DynamoDBCommitStateError(`Analytics event "${change.row.id}" is duplicated`);
1343
+ analytics.set(key, change.row);
1344
+ break;
1345
+ }
1346
+ case "apiKeys":
1347
+ if (change.operation === "insert") {
1348
+ rememberApiKey(await loadApiKeyByHash(store, change.row.hash));
1349
+ if (apiKeyHashes.has(change.row.hash)) break;
1350
+ rememberApiKey(await loadApiKey(store, change.row.id));
1351
+ if (apiKeys.has(change.row.id)) throw new DynamoDBCommitStateError(`API key id "${change.row.id}" already exists`);
1352
+ const inserted = {
1353
+ row: change.row,
1354
+ version: 1
1355
+ };
1356
+ apiKeys.set(change.row.id, inserted);
1357
+ apiKeyHashes.set(change.row.hash, change.row.id);
1358
+ } else {
1359
+ rememberApiKey(await loadApiKey(store, change.where.id));
1360
+ const current = apiKeys.get(change.where.id);
1361
+ if (current === void 0) return {
1362
+ committed: false,
1363
+ conflict: {
1364
+ changeIndex,
1365
+ reason: "not_found"
1366
+ }
1367
+ };
1368
+ apiKeys.set(change.where.id, {
1369
+ row: {
1370
+ ...current.row,
1371
+ revoked_at_ms: change.update.revokedAtMs
1372
+ },
1373
+ version: current.version
1374
+ });
1375
+ }
1376
+ break;
1377
+ }
1378
+ const relationCounts = /* @__PURE__ */ new Map();
1379
+ const ownedPatchCounts = /* @__PURE__ */ new Map();
1380
+ for (const patch of patches.values()) {
1381
+ for (const id of new Set([patch.bundle_id, patch.base_bundle_id])) relationCounts.set(id, (relationCounts.get(id) ?? 0) + 1);
1382
+ ownedPatchCounts.set(patch.bundle_id, (ownedPatchCounts.get(patch.bundle_id) ?? 0) + 1);
1383
+ }
1384
+ const channelReferenceCounts = /* @__PURE__ */ new Map();
1385
+ for (const release of releases.values()) channelReferenceCounts.set(release.channel_id, (channelReferenceCounts.get(release.channel_id) ?? 0) + 1);
1386
+ const actions = [];
1387
+ const originalChannels = new Map(originalChannelItems.map((item) => [item.sk, item]));
1388
+ for (const original of originalChannelItems) if (!channels.has(original.sk)) actions.push(...deleteChannelActions(store, original));
1389
+ for (const [id, row] of channels) {
1390
+ const original = originalChannels.get(id);
1391
+ const referenceCount = channelReferenceCounts.get(id) ?? 0;
1392
+ if (original === void 0) {
1393
+ actions.push(putChannel(store, row, original, referenceCount));
1394
+ actions.push({ Put: {
1395
+ TableName: store.tableName,
1396
+ Item: {
1397
+ pk: DYNAMODB_CHANNEL_NAME_PARTITION,
1398
+ sk: row.name,
1399
+ channel_id: id
1400
+ },
1401
+ ConditionExpression: "attribute_not_exists(#pk)",
1402
+ ExpressionAttributeNames: { "#pk": "pk" }
1403
+ } });
1404
+ } else {
1405
+ if (!rowsEqual(original.row, row)) throw new DynamoDBCommitStateError(`Channel "${id}" cannot be updated`);
1406
+ const delta = referenceCount - original.reference_count;
1407
+ if (delta !== 0) actions.push(updateChannelReferenceCount(store, original, delta));
1408
+ }
1409
+ }
1410
+ const originalBundles = new Map(originalBundleItems.map((item) => [item.sk, item]));
1411
+ for (const original of originalBundleItems) if (!bundles.has(original.sk)) actions.push(deleteAction(store, original));
1412
+ for (const [id, row] of bundles) {
1413
+ const original = originalBundles.get(id);
1414
+ const relationCount = relationCounts.get(id) ?? 0;
1415
+ const ownedPatchCount = ownedPatchCounts.get(id) ?? 0;
1416
+ if (original === void 0) actions.push(putNewBundle(store, row, relationCount, ownedPatchCount));
1417
+ else if (!rowsEqual(original.row, row)) actions.push(putUpdatedBundle(store, original, row, relationCount, ownedPatchCount));
1418
+ else {
1419
+ const relationDelta = relationCount - original.relation_count;
1420
+ const ownedPatchDelta = ownedPatchCount - original.owned_patch_count;
1421
+ if (relationDelta !== 0 || ownedPatchDelta !== 0) actions.push(updateBundleRelation(store, id, relationDelta, ownedPatchDelta));
1422
+ }
1423
+ }
1424
+ const originalPatches = new Map(originalPatchItems.map((item) => [item.sk, item]));
1425
+ for (const original of originalPatchItems) if (!patches.has(original.sk)) actions.push(deletePatch(store, original));
1426
+ for (const [id, row] of patches) {
1427
+ const original = originalPatches.get(id);
1428
+ if (original === void 0 || !rowsEqual(original.row, row)) actions.push(putPatch(store, row, original));
1429
+ }
1430
+ const originalReleases = new Map(originalReleaseItems.map((item) => [item.sk, item]));
1431
+ for (const original of originalReleaseItems) {
1432
+ if (releases.get(original.sk) !== void 0) continue;
1433
+ actions.push(deleteAction(store, original));
1434
+ actions.push({ Delete: {
1435
+ TableName: store.tableName,
1436
+ Key: {
1437
+ pk: DYNAMODB_RELEASE_ID_PARTITION,
1438
+ sk: original.sk
1439
+ },
1440
+ ConditionExpression: "#scopeKey = :scopeKey",
1441
+ ExpressionAttributeNames: { "#scopeKey": "scope_key" },
1442
+ ExpressionAttributeValues: { ":scopeKey": original.row.scope_key }
1443
+ } });
1444
+ }
1445
+ for (const [id, row] of releases) {
1446
+ const original = originalReleases.get(id);
1447
+ if (original === void 0) {
1448
+ actions.push({ Put: {
1449
+ TableName: store.tableName,
1450
+ Item: boundedDynamoDBMetadataItem(toDynamoDBReleaseItem(row)),
1451
+ ConditionExpression: "attribute_not_exists(#pk)",
1452
+ ExpressionAttributeNames: { "#pk": "pk" }
1453
+ } });
1454
+ actions.push({ Put: {
1455
+ TableName: store.tableName,
1456
+ Item: releaseLocatorItem(row),
1457
+ ConditionExpression: "attribute_not_exists(#pk)",
1458
+ ExpressionAttributeNames: { "#pk": "pk" }
1459
+ } });
1460
+ } else if (!rowsEqual(original.row, row)) {
1461
+ const moved = original.row.scope_key !== row.scope_key;
1462
+ if (moved) actions.push(deleteAction(store, original));
1463
+ actions.push({ Put: {
1464
+ TableName: store.tableName,
1465
+ Item: boundedDynamoDBMetadataItem(toDynamoDBReleaseItem(row, original.version + 1)),
1466
+ ConditionExpression: moved ? "attribute_not_exists(#pk)" : "#version = :version",
1467
+ ExpressionAttributeNames: moved ? { "#pk": "pk" } : { "#version": "version" },
1468
+ ...moved ? {} : { ExpressionAttributeValues: { ":version": original.version } }
1469
+ } });
1470
+ if (moved) actions.push({ Put: {
1471
+ TableName: store.tableName,
1472
+ Item: releaseLocatorItem(row),
1473
+ ConditionExpression: "#scopeKey = :scopeKey",
1474
+ ExpressionAttributeNames: { "#scopeKey": "scope_key" },
1475
+ ExpressionAttributeValues: { ":scopeKey": original.row.scope_key }
1476
+ } });
1477
+ }
1478
+ }
1479
+ const originalReleaseCatalogs = new Map(originalReleaseCatalogItems.map((item) => [item.sk, item]));
1480
+ for (const [scopeKey, row] of releaseCatalogs) {
1481
+ const original = originalReleaseCatalogs.get(scopeKey);
1482
+ if (original === void 0 || !rowsEqual(original.row, row)) actions.push({ Put: {
1483
+ TableName: store.tableName,
1484
+ Item: boundedDynamoDBCatalogItem(toDynamoDBReleaseCatalogItem(row, (original?.version ?? 0) + 1)),
1485
+ ConditionExpression: original ? "#version = :version" : "attribute_not_exists(#pk)",
1486
+ ExpressionAttributeNames: original ? { "#version": "version" } : { "#pk": "pk" },
1487
+ ...original ? { ExpressionAttributeValues: { ":version": original.version } } : {}
1488
+ } });
1489
+ }
1490
+ const changedReleaseIds = new Set([...new Set([...originalReleases.keys(), ...releases.keys()])].filter((id) => {
1491
+ const original = originalReleases.get(id)?.row;
1492
+ const next = releases.get(id);
1493
+ return original === void 0 || next === void 0 || !rowsEqual(original, next);
1494
+ }));
1495
+ const changedCatalogScopes = new Set([...releaseCatalogs].flatMap(([scopeKey, row]) => {
1496
+ const original = originalReleaseCatalogs.get(scopeKey)?.row;
1497
+ return original === void 0 || !rowsEqual(original, row) ? [scopeKey] : [];
1498
+ }));
1499
+ for (const expectation of input.expectations ?? []) {
1500
+ if (expectation.model === "releases" && !changedReleaseIds.has(expectation.id)) {
1501
+ const original = originalReleases.get(expectation.id);
1502
+ actions.push({ ConditionCheck: {
1503
+ TableName: store.tableName,
1504
+ Key: original === void 0 ? {
1505
+ pk: DYNAMODB_RELEASE_ID_PARTITION,
1506
+ sk: expectation.id
1507
+ } : {
1508
+ pk: original.pk,
1509
+ sk: original.sk
1510
+ },
1511
+ ConditionExpression: original === void 0 ? "attribute_not_exists(#pk)" : "#version = :version",
1512
+ ExpressionAttributeNames: original === void 0 ? { "#pk": "pk" } : { "#version": "version" },
1513
+ ...original === void 0 ? {} : { ExpressionAttributeValues: { ":version": original.version } }
1514
+ } });
1515
+ }
1516
+ if (expectation.model === "releaseCatalogs" && !changedCatalogScopes.has(expectation.scopeKey)) {
1517
+ const original = originalReleaseCatalogs.get(expectation.scopeKey);
1518
+ actions.push({ ConditionCheck: {
1519
+ TableName: store.tableName,
1520
+ Key: itemKey("release_catalogs", expectation.scopeKey),
1521
+ ConditionExpression: original === void 0 ? "attribute_not_exists(#pk)" : "#version = :version",
1522
+ ExpressionAttributeNames: original === void 0 ? { "#pk": "pk" } : { "#version": "version" },
1523
+ ...original === void 0 ? {} : { ExpressionAttributeValues: { ":version": original.version } }
1524
+ } });
1525
+ }
1526
+ }
1527
+ const counter = metadataUpdate(store, {
1528
+ bundles: bundles.size - originalBundles.size,
1529
+ bundle_patches: patches.size - originalPatches.size
1530
+ });
1531
+ if (counter !== void 0) actions.push(counter);
1532
+ for (const [key, row] of analytics) actions.push({ Put: {
1533
+ TableName: store.tableName,
1534
+ Item: boundedDynamoDBMetadataItem({
1535
+ pk: DYNAMODB_ANALYTICS_PARTITION,
1536
+ sk: key,
1537
+ version: 1,
1538
+ row
1539
+ }),
1540
+ ConditionExpression: "attribute_not_exists(#pk)",
1541
+ ExpressionAttributeNames: { "#pk": "pk" }
1542
+ } });
1543
+ for (const [id, current] of apiKeys) {
1544
+ const original = originalApiKeys.get(id);
1545
+ if (original !== void 0 && rowsEqual(original.row, current.row)) continue;
1546
+ actions.push({ Put: {
1547
+ TableName: store.tableName,
1548
+ Item: boundedDynamoDBMetadataItem(apiKeyItem(current.row, original === void 0 ? 1 : original.version + 1)),
1549
+ ConditionExpression: original ? "#version = :version" : "attribute_not_exists(#pk)",
1550
+ ExpressionAttributeNames: original ? { "#version": "version" } : { "#pk": "pk" },
1551
+ ...original ? { ExpressionAttributeValues: { ":version": original.version } } : {}
1552
+ } });
1553
+ if (original === void 0) actions.push({ Put: {
1554
+ TableName: store.tableName,
1555
+ Item: {
1556
+ pk: DYNAMODB_API_KEY_HASH_PARTITION,
1557
+ sk: current.row.hash,
1558
+ api_key_id: current.row.id
1559
+ },
1560
+ ConditionExpression: "attribute_not_exists(#pk)",
1561
+ ExpressionAttributeNames: { "#pk": "pk" }
1562
+ } });
1563
+ }
1564
+ if (actions.length > 0) await commitDynamoDBTransaction(store, actions);
1565
+ return { committed: true };
1566
+ };
1567
+ const isDynamoDBTransactionConflict = (error) => typeof error === "object" && error !== null && Reflect.get(error, "name") === "TransactionCanceledException";
1568
+ const createDynamoDBCommit = (store) => async (input) => {
1569
+ try {
1570
+ return await compileAndCommitDynamoDBChanges(store, input);
1571
+ } catch (error) {
1572
+ if (!isDynamoDBTransactionConflict(error)) throw error;
1573
+ return compileAndCommitDynamoDBChanges(store, input);
1574
+ }
1575
+ };
1576
+ const DYNAMODB_ANALYTICS_PARTITION = "bundle_events";
1577
+ const DYNAMODB_API_KEY_PARTITION = "api_keys";
1578
+ const DYNAMODB_API_KEY_HASH_PARTITION = "_hot-updater#api-key-hashes";
1579
+ const hasValidBundleEventShape = (value) => {
1580
+ const type = field(value, "type");
1581
+ const fromBundleId = field(value, "from_bundle_id");
1582
+ const updateStrategy = field(value, "update_strategy");
1583
+ return (type === "UPDATE_APPLIED" || type === "RECOVERED" || type === "RELEASE_ADOPTED") && typeof fromBundleId === "string" && (updateStrategy === "fingerprint" || updateStrategy === "appVersion") || type === "UNCHANGED" && fromBundleId === null && updateStrategy === null;
1584
+ };
1585
+ const isBundleEventRow = (value) => typeof value === "object" && value !== null && typeof field(value, "id") === "string" && typeof field(value, "install_id") === "string" && isNullableString(field(value, "from_release_id")) && isNullableString(field(value, "to_release_id")) && typeof field(value, "to_bundle_id") === "string" && (field(value, "platform") === "ios" || field(value, "platform") === "android") && typeof field(value, "received_at_ms") === "number" && hasValidBundleEventShape(value);
1586
+ const isApiKeyRow = (value) => typeof value === "object" && value !== null && typeof field(value, "id") === "string" && typeof field(value, "hash") === "string" && typeof field(value, "name") === "string" && typeof field(value, "prefix") === "string" && field(value, "role") === "client" && typeof field(value, "created_at_ms") === "number" && (field(value, "revoked_at_ms") === null || typeof field(value, "revoked_at_ms") === "number");
1587
+ const parseOfficialRowItem = (value, partition, isRow) => {
1588
+ if (value.pk !== partition || typeof value.sk !== "string" || typeof value.version !== "number" || !isRow(value.row)) throw new DynamoDBStoredItemError();
1589
+ return {
1590
+ row: value.row,
1591
+ version: value.version
1592
+ };
1593
+ };
1594
+ const timestampSortKey = (timestampMs) => Math.trunc(timestampMs).toString().padStart(16, "0");
1595
+ const analyticsSortKey = (row) => `${timestampSortKey(row.received_at_ms)}#${row.id}`;
1596
+ const createDynamoDBAnalyticsTable = (store) => ({
1597
+ async append(row) {
1598
+ await store.client.send(new _aws_sdk_lib_dynamodb.PutCommand({
1599
+ TableName: store.tableName,
1600
+ Item: boundedDynamoDBMetadataItem({
1601
+ pk: DYNAMODB_ANALYTICS_PARTITION,
1602
+ sk: analyticsSortKey(row),
1603
+ version: 1,
1604
+ row
1605
+ }),
1606
+ ConditionExpression: "attribute_not_exists(#pk)",
1607
+ ExpressionAttributeNames: { "#pk": "pk" }
1608
+ }));
1609
+ },
1610
+ async scan(input) {
1611
+ if (input.limit <= 0) return [];
1612
+ if (input.after !== void 0 && input.after.receivedAtMs >= input.beforeReceivedAtMs) return [];
1613
+ const rows = [];
1614
+ const afterKey = input.after === void 0 ? void 0 : `${timestampSortKey(input.after.receivedAtMs)}#${input.after.id}`;
1615
+ let exclusiveStartKey;
1616
+ do {
1617
+ const page = await store.client.send(new _aws_sdk_lib_dynamodb.QueryCommand({
1618
+ TableName: store.tableName,
1619
+ ExclusiveStartKey: exclusiveStartKey,
1620
+ KeyConditionExpression: afterKey === void 0 ? "#pk = :pk AND #sk < :before" : "#pk = :pk AND #sk BETWEEN :after AND :before",
1621
+ ExpressionAttributeNames: {
1622
+ "#pk": "pk",
1623
+ "#sk": "sk"
1624
+ },
1625
+ ExpressionAttributeValues: {
1626
+ ":before": `${timestampSortKey(input.beforeReceivedAtMs)}#`,
1627
+ ":pk": DYNAMODB_ANALYTICS_PARTITION,
1628
+ ...afterKey === void 0 ? {} : { ":after": afterKey }
1629
+ },
1630
+ Limit: input.limit - rows.length + (afterKey === void 0 ? 0 : 1),
1631
+ ScanIndexForward: true
1632
+ }));
1633
+ for (const item of page.Items ?? []) {
1634
+ if (item.sk === afterKey) continue;
1635
+ rows.push(parseOfficialRowItem(item, DYNAMODB_ANALYTICS_PARTITION, isBundleEventRow).row);
1636
+ if (rows.length === input.limit) return rows;
1637
+ }
1638
+ exclusiveStartKey = page.LastEvaluatedKey;
1639
+ } while (exclusiveStartKey !== void 0);
1640
+ return rows;
1641
+ }
1642
+ });
1643
+ const apiKeyItem = (row, version) => ({
1644
+ pk: DYNAMODB_API_KEY_PARTITION,
1645
+ sk: row.id,
1646
+ version,
1647
+ row
1648
+ });
1649
+ const loadApiKey = async (store, id) => {
1650
+ const result = await store.client.send(new _aws_sdk_lib_dynamodb.GetCommand({
1651
+ TableName: store.tableName,
1652
+ Key: {
1653
+ pk: DYNAMODB_API_KEY_PARTITION,
1654
+ sk: id
1655
+ },
1656
+ ConsistentRead: true
1657
+ }));
1658
+ return result.Item === void 0 ? null : parseOfficialRowItem(result.Item, DYNAMODB_API_KEY_PARTITION, isApiKeyRow);
1659
+ };
1660
+ const createDynamoDBApiKeyTable = (store) => {
1661
+ const findByHash = async (hash) => {
1662
+ const lookup = await store.client.send(new _aws_sdk_lib_dynamodb.GetCommand({
1663
+ TableName: store.tableName,
1664
+ Key: {
1665
+ pk: DYNAMODB_API_KEY_HASH_PARTITION,
1666
+ sk: hash
1667
+ },
1668
+ ConsistentRead: true
1669
+ }));
1670
+ const id = lookup.Item?.api_key_id;
1671
+ if (lookup.Item === void 0) return null;
1672
+ if (typeof id !== "string") throw new DynamoDBStoredItemError();
1673
+ return (await loadApiKey(store, id))?.row ?? null;
1674
+ };
1675
+ return {
1676
+ async create(row) {
1677
+ if (await findByHash(row.hash) !== null) return "existing";
1678
+ try {
1679
+ await commitDynamoDBTransaction(store, [{ Put: {
1680
+ TableName: store.tableName,
1681
+ Item: boundedDynamoDBMetadataItem(apiKeyItem(row, 1)),
1682
+ ConditionExpression: "attribute_not_exists(#pk)",
1683
+ ExpressionAttributeNames: { "#pk": "pk" }
1684
+ } }, { Put: {
1685
+ TableName: store.tableName,
1686
+ Item: {
1687
+ pk: DYNAMODB_API_KEY_HASH_PARTITION,
1688
+ sk: row.hash,
1689
+ api_key_id: row.id
1690
+ },
1691
+ ConditionExpression: "attribute_not_exists(#pk)",
1692
+ ExpressionAttributeNames: { "#pk": "pk" }
1693
+ } }]);
1694
+ return "created";
1695
+ } catch (error) {
1696
+ if (await findByHash(row.hash) !== null) return "existing";
1697
+ throw error;
1698
+ }
1699
+ },
1700
+ findByHash,
1701
+ async list() {
1702
+ const rows = [];
1703
+ let exclusiveStartKey;
1704
+ do {
1705
+ const page = await store.client.send(new _aws_sdk_lib_dynamodb.QueryCommand({
1706
+ TableName: store.tableName,
1707
+ ExclusiveStartKey: exclusiveStartKey,
1708
+ KeyConditionExpression: "#pk = :pk",
1709
+ ExpressionAttributeNames: { "#pk": "pk" },
1710
+ ExpressionAttributeValues: { ":pk": DYNAMODB_API_KEY_PARTITION },
1711
+ ConsistentRead: true
1712
+ }));
1713
+ rows.push(...(page.Items ?? []).map((item) => parseOfficialRowItem(item, DYNAMODB_API_KEY_PARTITION, isApiKeyRow).row));
1714
+ exclusiveStartKey = page.LastEvaluatedKey;
1715
+ } while (exclusiveStartKey !== void 0);
1716
+ return rows.sort((left, right) => right.created_at_ms - left.created_at_ms || left.id.localeCompare(right.id));
1717
+ },
1718
+ async revoke({ id, revokedAtMs }) {
1719
+ const current = await loadApiKey(store, id);
1720
+ if (current === null) return null;
1721
+ const row = {
1722
+ ...current.row,
1723
+ revoked_at_ms: revokedAtMs
1724
+ };
1725
+ await store.client.send(new _aws_sdk_lib_dynamodb.PutCommand({
1726
+ TableName: store.tableName,
1727
+ Item: boundedDynamoDBMetadataItem(apiKeyItem(row, current.version + 1)),
1728
+ ConditionExpression: "#version = :currentVersion",
1729
+ ExpressionAttributeNames: { "#version": "version" },
1730
+ ExpressionAttributeValues: { ":currentVersion": current.version }
1731
+ }));
1732
+ return row;
1733
+ }
1734
+ };
1735
+ };
1736
+ const DYNAMODB_UPDATE_INDEX_NAME = "hot-updater-update-index";
1737
+ const dynamoDB = (config) => {
1738
+ const { apiBasePath = "/release-catalogs", cloudfrontDistributionId, shouldWaitForInvalidation = false, tableName, ...clientConfig } = config;
1739
+ const client = _aws_sdk_lib_dynamodb.DynamoDBDocumentClient.from(new _aws_sdk_client_dynamodb.DynamoDBClient(clientConfig), { marshallOptions: { removeUndefinedValues: true } });
1740
+ const cloudFront = cloudfrontDistributionId ? new _aws_sdk_client_cloudfront.CloudFrontClient({
1741
+ credentials: clientConfig.credentials,
1742
+ region: clientConfig.region
1743
+ }) : null;
1744
+ const store = {
1745
+ client,
1746
+ tableName
1747
+ };
1748
+ const crud = createDynamoDBCrud(store, DYNAMODB_UPDATE_INDEX_NAME);
1749
+ const invalidateUpdateRoutes = async () => {
1750
+ if (!cloudFront || !cloudfrontDistributionId) return;
1751
+ try {
1752
+ await invalidateCloudFront(cloudFront, cloudfrontDistributionId, [`${apiBasePath.replace(/\/+$/, "")}/*`], { shouldWait: shouldWaitForInvalidation });
1753
+ } catch (error) {
1754
+ console.warn("[hot-updater/aws] CloudFront invalidation failed; continuing without cache invalidation.", {
1755
+ distributionId: cloudfrontDistributionId,
1756
+ error: error instanceof Error ? error.message : "Unknown error"
1757
+ });
1758
+ }
1759
+ };
1760
+ const adapter = (0, _hot_updater_plugin_core_internal.createDatabasePluginAdapter)("dynamoDB", {
1761
+ ...crud,
1762
+ commit: createDynamoDBCommit(store),
1763
+ dispose: async () => {
1764
+ client.destroy();
1765
+ cloudFront?.destroy();
1766
+ }
1767
+ });
1768
+ return (0, _hot_updater_plugin_core.createDatabasePlugin)({
1769
+ name: "dynamoDB",
1770
+ models: {
1771
+ ...adapter.models,
1772
+ bundlePatches: createDynamoDBBundlePatchTable(store, DYNAMODB_UPDATE_INDEX_NAME),
1773
+ analytics: createDynamoDBAnalyticsTable(store),
1774
+ apiKeys: createDynamoDBApiKeyTable(store)
1775
+ },
1776
+ async commit(input) {
1777
+ const result = await adapter.commit(input);
1778
+ if (result.committed && input.changes.some(({ model }) => model === "bundles" || model === "bundlePatches")) await invalidateUpdateRoutes();
1779
+ return result;
1780
+ },
1781
+ dispose: adapter.dispose
1782
+ });
1783
+ };
1417
1784
  //#endregion
1418
1785
  //#region src/runtimeAwsConfig.ts
1419
1786
  const truthyValues = new Set([
@@ -1450,477 +1817,173 @@ const applySsmRuntimeAwsConfig = (config) => {
1450
1817
  };
1451
1818
  };
1452
1819
  //#endregion
1453
- //#region src/utils/streamToString.ts
1454
- const streamToString = (stream) => {
1455
- return new Promise((resolve, reject) => {
1456
- const chunks = [];
1457
- stream.on("data", (chunk) => chunks.push(chunk));
1458
- stream.on("error", reject);
1459
- stream.on("end", () => resolve(Buffer.concat(chunks).toString("utf8")));
1460
- });
1461
- };
1462
- //#endregion
1463
- //#region src/s3Database.ts
1464
- const DEFAULT_INVALIDATION_POLL_INTERVAL_MS = 2e3;
1465
- const DEFAULT_INVALIDATION_TIMEOUT_MS = 300 * 1e3;
1466
- const S3_LIST_OBJECTS_CONCURRENCY = 4;
1467
- const S3_DIRECTORY_DELIMITER = "/";
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 isLegacyBundleStorageDirectoryPrefix(prefix) {
1519
- const lastSegment = getLastDirectorySegment(prefix);
1520
- return lastSegment !== void 0 && /^[0-9a-f]{8}-[0-9a-f]{4}-7[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(lastSegment);
1521
- }
1522
- function isUpdateJsonKey(key) {
1523
- return key.endsWith(`${S3_DIRECTORY_DELIMITER}update.json`);
1524
- }
1525
- function isUuidChannelUpdateJsonKey(key, rootPrefix, uuidChannels) {
1526
- const [channel, platform, target, fileName, ...rest] = getRelativeDirectoryPrefix(key, rootPrefix).split(S3_DIRECTORY_DELIMITER);
1527
- return channel !== void 0 && uuidChannels.has(channel) && (platform === "ios" || platform === "android") && target !== void 0 && target.length > 0 && fileName === "update.json" && rest.length === 0;
1528
- }
1529
- async function mapWithConcurrency(items, concurrency, mapper) {
1530
- const results = [];
1531
- let nextIndex = 0;
1532
- const workerCount = Math.min(concurrency, items.length);
1533
- await Promise.all(Array.from({ length: workerCount }, async () => {
1534
- while (nextIndex < items.length) {
1535
- const index = nextIndex;
1536
- nextIndex += 1;
1537
- const item = items[index];
1538
- if (item === void 0) break;
1539
- results[index] = await mapper(item, index);
1540
- }
1541
- }));
1542
- return results.filter((result) => result !== void 0);
1543
- }
1544
- /**
1545
- * Loads JSON data from S3.
1546
- * Returns null if NoSuchKey error occurs.
1547
- */
1548
- async function loadJsonFromS3(client, bucket, key) {
1549
- try {
1550
- const { Body } = await client.send(new _aws_sdk_client_s3.GetObjectCommand({
1551
- Bucket: bucket,
1552
- Key: key
1553
- }));
1554
- if (!Body) return null;
1555
- const bodyContents = await streamToString(Body);
1556
- return JSON.parse(bodyContents);
1557
- } catch (e) {
1558
- if (e instanceof _aws_sdk_client_s3.NoSuchKey) return null;
1559
- if (isArchivedS3ObjectError(e)) throw createArchivedS3ObjectError({
1560
- bucket,
1561
- key,
1562
- error: e
1563
- });
1564
- throw e;
1565
- }
1566
- }
1567
- /**
1568
- * Converts data to JSON string and uploads to S3.
1569
- */
1570
- async function uploadJsonToS3(client, bucket, key, data) {
1571
- const Body = JSON.stringify(data);
1572
- const ContentType = src_default.getType(key) ?? "application/json";
1573
- await client.send(new _aws_sdk_client_s3.PutObjectCommand({
1574
- Bucket: bucket,
1575
- Key: key,
1576
- Body,
1577
- ContentType,
1578
- CacheControl: "max-age=31536000"
1579
- }));
1580
- }
1581
- async function listObjectsInS3(client, bucketName, prefix, rootPrefix = "") {
1582
- const normalizedRootPrefix = normalizeDirectoryPrefix(rootPrefix);
1583
- const listPrefix = async (currentPrefix, delimiter = S3_DIRECTORY_DELIMITER) => {
1584
- let continuationToken;
1585
- const keys = [];
1586
- const commonPrefixes = /* @__PURE__ */ new Set();
1587
- do {
1588
- const response = await client.send(new _aws_sdk_client_s3.ListObjectsV2Command({
1589
- Bucket: bucketName,
1590
- Prefix: currentPrefix,
1591
- Delimiter: delimiter ?? void 0,
1592
- ContinuationToken: continuationToken
1593
- }));
1594
- const found = (response.Contents ?? []).map((item) => item.Key).filter((key) => !!key);
1595
- keys.push(...found);
1596
- for (const commonPrefix of response.CommonPrefixes ?? []) if (commonPrefix.Prefix) commonPrefixes.add(commonPrefix.Prefix);
1597
- continuationToken = response.NextContinuationToken;
1598
- } while (continuationToken);
1599
- return {
1600
- commonPrefixes: Array.from(commonPrefixes),
1601
- keys
1602
- };
1603
- };
1604
- const collectUpdateJsonKeys = async (currentPrefix) => {
1605
- const { commonPrefixes, keys } = await listPrefix(currentPrefix);
1606
- const depth = getDirectoryDepth(currentPrefix, normalizedRootPrefix);
1607
- if (depth >= 2) return [...keys.filter(isUpdateJsonKey), ...commonPrefixes.map((commonPrefix) => `${commonPrefix}update.json`)];
1608
- const uuidPrefixes = depth === 0 ? commonPrefixes.filter(isLegacyBundleStorageDirectoryPrefix) : [];
1609
- const uuidPrefixSet = new Set(uuidPrefixes);
1610
- const nestedKeys = await mapWithConcurrency(depth === 0 ? commonPrefixes.filter((commonPrefix) => !uuidPrefixSet.has(commonPrefix)) : depth === 1 ? commonPrefixes.filter(isPlatformDirectoryPrefix) : commonPrefixes, S3_LIST_OBJECTS_CONCURRENCY, (nextPrefix) => collectUpdateJsonKeys(nextPrefix));
1611
- const uuidChannels = new Set(uuidPrefixes.map(getLastDirectorySegment).filter((segment) => !!segment));
1612
- const uuidChannelKeys = (await mapWithConcurrency(Array.from(new Set(Array.from(uuidChannels, (channel) => `${normalizedRootPrefix}${channel[0]}`))), S3_LIST_OBJECTS_CONCURRENCY, async (scanPrefix) => (await listPrefix(scanPrefix, null)).keys)).flat().filter((key) => isUuidChannelUpdateJsonKey(key, normalizedRootPrefix, uuidChannels));
1613
- return [...nestedKeys.flat(), ...uuidChannelKeys];
1614
- };
1615
- const normalizedPrefix = normalizeDirectoryPrefix(prefix);
1616
- return Array.from(new Set(await collectUpdateJsonKeys(normalizedPrefix)));
1617
- }
1618
- async function deleteObjectInS3(client, bucketName, key) {
1619
- await client.send(new _aws_sdk_client_s3.DeleteObjectCommand({
1620
- Bucket: bucketName,
1621
- Key: key
1622
- }));
1623
- }
1624
- /**
1625
- * Invalidates CloudFront cache for the given paths.
1626
- */
1627
- async function invalidateCloudFront(client, distributionId, paths, options) {
1628
- if (paths.length === 0) return;
1629
- const timestamp = Date.now();
1630
- try {
1631
- const response = await client.send(new _aws_sdk_client_cloudfront.CreateInvalidationCommand({
1632
- DistributionId: distributionId,
1633
- InvalidationBatch: {
1634
- CallerReference: `invalidation-${timestamp}`,
1635
- Paths: {
1636
- Quantity: paths.length,
1637
- Items: paths
1638
- }
1639
- }
1640
- }));
1641
- if (!options?.shouldWaitForInvalidation) return;
1642
- const invalidationId = response.Invalidation?.Id;
1643
- if (!invalidationId) throw new Error("CloudFront invalidation response is missing Invalidation.Id");
1644
- if (response.Invalidation?.Status === "Completed") return;
1645
- const timeoutMs = DEFAULT_INVALIDATION_TIMEOUT_MS;
1646
- const pollIntervalMs = DEFAULT_INVALIDATION_POLL_INTERVAL_MS;
1647
- const deadline = Date.now() + timeoutMs;
1648
- while (Date.now() < deadline) {
1649
- await sleep(pollIntervalMs);
1650
- if ((await client.send(new _aws_sdk_client_cloudfront.GetInvalidationCommand({
1651
- DistributionId: distributionId,
1652
- Id: invalidationId
1653
- }))).Invalidation?.Status === "Completed") return;
1654
- }
1655
- throw new Error(`Timed out waiting for CloudFront invalidation ${invalidationId} to complete after ${timeoutMs}ms`);
1656
- } catch (error) {
1657
- if (options?.shouldWaitForInvalidation) throw error;
1658
- const message = error instanceof Error ? error.message : "Unknown invalidation error";
1659
- console.warn(`[hot-updater/aws] CloudFront invalidation failed for distribution ${distributionId}; continuing without cache invalidation.`, {
1660
- error: message,
1661
- paths
1662
- });
1663
- }
1664
- }
1665
- const s3Database = (0, _hot_updater_plugin_core.createBlobDatabasePlugin)({
1666
- name: "s3Database",
1667
- factory: (config) => {
1668
- const { basePath, bucketName, cloudfrontDistributionId, apiBasePath = "/api/check-update", shouldWaitForInvalidation = false, ...s3Config } = config;
1669
- const client = new _aws_sdk_client_s3.S3Client(applyS3RuntimeAwsConfig(s3Config));
1670
- const { fromStorageKey, toStorageKey } = createDatabaseKeyBuilder(basePath);
1671
- const rootPrefix = toStorageKey("");
1672
- const cloudfrontClient = cloudfrontDistributionId ? new _aws_sdk_client_cloudfront.CloudFrontClient({
1673
- credentials: s3Config.credentials,
1674
- region: s3Config.region
1675
- }) : void 0;
1676
- return {
1677
- apiBasePath,
1678
- listObjects: (prefix) => listObjectsInS3(client, bucketName, toStorageKey(prefix), rootPrefix).then((keys) => keys.map(fromStorageKey)),
1679
- loadObject: (key) => loadJsonFromS3(client, bucketName, toStorageKey(key)),
1680
- uploadObject: (key, data) => uploadJsonToS3(client, bucketName, toStorageKey(key), data),
1681
- deleteObject: (key) => deleteObjectInS3(client, bucketName, toStorageKey(key)),
1682
- shouldSkipLoadObjectError: (error) => error instanceof Error && error.name === "S3ArchivedObjectError",
1683
- invalidatePaths: (pathsToInvalidate) => {
1684
- if (cloudfrontClient && cloudfrontDistributionId && pathsToInvalidate.length > 0) return invalidateCloudFront(cloudfrontClient, cloudfrontDistributionId, pathsToInvalidate, { shouldWaitForInvalidation });
1685
- return Promise.resolve();
1686
- }
1687
- };
1688
- }
1689
- });
1690
- //#endregion
1691
- //#region src/s3Storage.ts
1692
- const s3Storage = (0, _hot_updater_plugin_core.createUniversalStoragePlugin)({
1693
- name: "s3Storage",
1694
- supportedProtocol: "s3",
1695
- factory: (config) => {
1696
- const { bucketName, ...s3Config } = config;
1697
- const client = new _aws_sdk_client_s3.S3Client(applyS3RuntimeAwsConfig(s3Config));
1698
- const normalizedBasePath = config.basePath?.replace(/^\/+|\/+$/g, "") ?? "";
1699
- const getStorageKey = (0, _hot_updater_plugin_core.createStorageKeyBuilder)(normalizedBasePath);
1700
- const getListPrefix = (prefix = "") => {
1701
- const value = [normalizedBasePath, prefix.replace(/^\/+|\/+$/g, "")].filter(Boolean).join("/");
1702
- return value ? `${value}/` : "";
1703
- };
1704
- const getRelativeKey = (key) => {
1705
- if (!normalizedBasePath) return key;
1706
- const basePrefix = `${normalizedBasePath}/`;
1707
- return key.startsWith(basePrefix) ? key.slice(basePrefix.length) : key;
1708
- };
1709
- return {
1710
- node: {
1711
- async listObjects(prefix) {
1712
- const objects = [];
1713
- let continuationToken;
1714
- do {
1715
- const response = await client.send(new _aws_sdk_client_s3.ListObjectsV2Command({
1716
- Bucket: bucketName,
1717
- ContinuationToken: continuationToken,
1718
- Prefix: getListPrefix(prefix)
1719
- }));
1720
- for (const object of response.Contents ?? []) {
1721
- if (!object.Key) continue;
1722
- objects.push({
1723
- key: getRelativeKey(object.Key),
1724
- lastModifiedAt: object.LastModified,
1725
- size: object.Size ?? 0,
1726
- storageUri: `s3://${bucketName}/${object.Key}`
1727
- });
1728
- }
1729
- continuationToken = response.NextContinuationToken;
1730
- } while (continuationToken);
1731
- return objects;
1732
- },
1733
- async deleteObjects(relativeKeys) {
1734
- const keys = relativeKeys.map((key) => getStorageKey(key));
1735
- for (let offset = 0; offset < keys.length; offset += 1e3) {
1736
- const batch = keys.slice(offset, offset + 1e3);
1737
- if (batch.length === 0) continue;
1738
- const response = await client.send(new _aws_sdk_client_s3.DeleteObjectsCommand({
1739
- Bucket: bucketName,
1740
- Delete: {
1741
- Objects: batch.map((Key) => ({ Key })),
1742
- Quiet: true
1743
- }
1744
- }));
1745
- if (response.Errors && response.Errors.length > 0) throw new Error(`Failed to delete ${response.Errors.length} S3 object(s).`);
1746
- }
1747
- },
1748
- async delete(storageUri) {
1749
- const { bucket, key } = (0, _hot_updater_plugin_core.parseStorageUri)(storageUri, "s3");
1750
- if (bucket !== bucketName) throw new Error(`Bucket name mismatch: expected "${bucketName}", but found "${bucket}".`);
1751
- const listCommand = new _aws_sdk_client_s3.ListObjectsV2Command({
1752
- Bucket: bucketName,
1753
- Prefix: key
1754
- });
1755
- const listResponse = await client.send(listCommand);
1756
- if (listResponse.Contents && listResponse.Contents.length > 0) {
1757
- const deleteCommand = new _aws_sdk_client_s3.DeleteObjectsCommand({
1758
- Bucket: bucketName,
1759
- Delete: {
1760
- Objects: listResponse.Contents.map((obj) => ({ Key: obj.Key })),
1761
- Quiet: true
1762
- }
1763
- });
1764
- await client.send(deleteCommand);
1765
- return;
1766
- }
1767
- throw new Error("Bundle Not Found");
1768
- },
1769
- async upload(key, filePath) {
1770
- const Body = await fs_promises.default.readFile(filePath);
1771
- const ContentType = (0, _hot_updater_plugin_core.getContentType)(filePath);
1772
- const Key = getStorageKey(key, path.default.basename(filePath));
1773
- const response = await new _aws_sdk_lib_storage.Upload({
1774
- client,
1775
- params: {
1776
- ContentType,
1777
- Bucket: bucketName,
1778
- Key,
1779
- Body,
1780
- CacheControl: "max-age=31536000"
1781
- }
1782
- }).done();
1783
- if (!response.Bucket || !response.Key) throw new Error("Upload Failed");
1784
- return { storageUri: `s3://${bucketName}/${Key}` };
1785
- },
1786
- async exists(storageUri) {
1787
- const { bucket, key } = (0, _hot_updater_plugin_core.parseStorageUri)(storageUri, "s3");
1788
- if (bucket !== bucketName) throw new Error(`Bucket name mismatch: expected "${bucketName}", but found "${bucket}".`);
1789
- try {
1790
- await client.send(new _aws_sdk_client_s3.HeadObjectCommand({
1791
- Bucket: bucketName,
1792
- Key: key
1793
- }));
1794
- return true;
1795
- } catch (error) {
1796
- if (error instanceof Error && (error.name === "NotFound" || error.name === "NoSuchKey")) return false;
1797
- throw error;
1798
- }
1799
- },
1800
- async downloadFile(storageUri, filePath) {
1801
- const { bucket, key } = (0, _hot_updater_plugin_core.parseStorageUri)(storageUri, "s3");
1802
- if (bucket !== bucketName) throw new Error(`Bucket name mismatch: expected "${bucketName}", but found "${bucket}".`);
1803
- const response = await client.send(new _aws_sdk_client_s3.GetObjectCommand({
1804
- Bucket: bucket,
1805
- Key: key
1806
- }));
1807
- if (!response.Body) throw new Error("S3 object body is empty");
1808
- await fs_promises.default.mkdir(path.default.dirname(filePath), { recursive: true });
1809
- await fs_promises.default.writeFile(filePath, await response.Body.transformToByteArray());
1810
- }
1811
- },
1812
- runtime: {
1813
- async readText(storageUri) {
1814
- const { bucket, key } = (0, _hot_updater_plugin_core.parseStorageUri)(storageUri, "s3");
1815
- if (bucket !== bucketName) throw new Error(`Bucket name mismatch: expected "${bucketName}", but found "${bucket}".`);
1816
- try {
1817
- const response = await client.send(new _aws_sdk_client_s3.GetObjectCommand({
1818
- Bucket: bucket,
1819
- Key: key
1820
- }));
1821
- if (!response.Body) return null;
1822
- return response.Body.transformToString();
1823
- } catch (error) {
1824
- if (error instanceof Error && error.name === "NoSuchKey") return null;
1825
- throw error;
1826
- }
1827
- },
1828
- async getDownloadUrl(storageUri) {
1829
- const { bucket, key } = (0, _hot_updater_plugin_core.parseStorageUri)(storageUri, "s3");
1830
- if (!bucket || !key) throw new Error("Invalid S3 storage URI: missing bucket or key");
1831
- try {
1832
- const signedUrl = await (0, _aws_sdk_s3_request_presigner.getSignedUrl)(client, new _aws_sdk_client_s3.GetObjectCommand({
1833
- Bucket: bucket,
1834
- Key: key
1835
- }), { expiresIn: 3600 });
1836
- if (!signedUrl) throw new Error("Failed to presign S3 URL");
1837
- return { fileUrl: signedUrl };
1838
- } catch (e) {
1839
- throw new Error(e instanceof Error ? `Failed to presign S3 URL: ${e.message}` : "Failed to presign S3 URL");
1840
- }
1841
- }
1842
- }
1843
- };
1844
- }
1845
- });
1846
- //#endregion
1847
- //#region src/withCloudFrontSignedUrl.ts
1820
+ //#region src/cloudFrontDownloadUrl.ts
1848
1821
  const ONE_YEAR_IN_SECONDS = 3600 * 24 * 365;
1849
1822
  const privateKeyCache = /* @__PURE__ */ new Map();
1850
1823
  const getPrivateKeyFromSsm = async (region, parameterName) => {
1851
- if (!region) throw new Error(`Invalid AWS region format: ${region}. Expected format like 'us-east-1' or 'ap-southeast-1'`);
1852
- const parameter = (await new _aws_sdk_client_ssm.SSM(applySsmRuntimeAwsConfig({ region })).getParameter({
1824
+ const value = (await new _aws_sdk_client_ssm.SSM(applySsmRuntimeAwsConfig({ region })).getParameter({
1853
1825
  Name: parameterName,
1854
1826
  WithDecryption: true
1855
- })).Parameter;
1856
- if (!parameter) throw new Error(`Failed to retrieve private key from SSM parameter: ${parameterName}`);
1857
- const parameterValue = parameter.Value;
1858
- if (!parameterValue) throw new Error(`Failed to retrieve private key from SSM parameter: ${parameterName}`);
1859
- let keyPair;
1860
- try {
1861
- keyPair = JSON.parse(parameterValue);
1862
- } catch (error) {
1863
- throw new Error(`Invalid JSON format in SSM parameter: ${parameterName}. ${error instanceof Error ? error.message : String(error)}`);
1864
- }
1865
- const privateKey = keyPair.privateKey;
1866
- if (!privateKey || typeof privateKey !== "string") throw new Error(`Invalid private key format in SSM parameter: ${parameterName}`);
1827
+ })).Parameter?.Value;
1828
+ if (!value) throw new Error(`CloudFront private key is missing: ${parameterName}`);
1829
+ const privateKey = JSON.parse(value).privateKey;
1830
+ if (typeof privateKey !== "string" || privateKey.length === 0) throw new Error(`Invalid CloudFront private key: ${parameterName}`);
1867
1831
  return privateKey;
1868
1832
  };
1869
1833
  const resolvePrivateKey = (config) => {
1870
- if ("getPrivateKey" in config && typeof config.getPrivateKey === "function") return config.getPrivateKey();
1834
+ if (config.getPrivateKey) return config.getPrivateKey();
1871
1835
  const cacheKey = `${config.ssmRegion}:${config.ssmParameterName}`;
1872
- const cachedPrivateKey = privateKeyCache.get(cacheKey);
1873
- if (cachedPrivateKey) return cachedPrivateKey;
1874
- const privateKeyPromise = getPrivateKeyFromSsm(config.ssmRegion, config.ssmParameterName).catch((error) => {
1836
+ const cached = privateKeyCache.get(cacheKey);
1837
+ if (cached) return cached;
1838
+ const pending = getPrivateKeyFromSsm(config.ssmRegion, config.ssmParameterName).catch((error) => {
1875
1839
  privateKeyCache.delete(cacheKey);
1876
1840
  throw error;
1877
1841
  });
1878
- privateKeyCache.set(cacheKey, privateKeyPromise);
1879
- return privateKeyPromise;
1842
+ privateKeyCache.set(cacheKey, pending);
1843
+ return pending;
1880
1844
  };
1881
- const resolvePublicBaseUrl = async (config, context) => {
1882
- const publicBaseUrl = typeof config.publicBaseUrl === "function" ? await config.publicBaseUrl(context) : config.publicBaseUrl;
1883
- if (!publicBaseUrl) throw new Error("CloudFront publicBaseUrl resolver returned an empty URL");
1884
- return publicBaseUrl;
1845
+ const cloudFrontDownloadUrl = (config) => async ({ storageUri }) => {
1846
+ const storageUrl = new URL(storageUri);
1847
+ if (storageUrl.protocol !== "s3:") throw new Error("CloudFront download URLs require an s3 storage URI.");
1848
+ const url = new URL(config.publicBaseUrl);
1849
+ url.pathname = storageUrl.pathname;
1850
+ url.search = "";
1851
+ return { url: (0, _aws_sdk_cloudfront_signer.getSignedUrl)({
1852
+ url: url.toString(),
1853
+ keyPairId: config.keyPairId,
1854
+ privateKey: await resolvePrivateKey(config),
1855
+ dateLessThan: new Date(Date.now() + (config.expiresSeconds ?? ONE_YEAR_IN_SECONDS) * 1e3).toISOString()
1856
+ }) };
1885
1857
  };
1886
- const withCloudFrontSignedUrl = (storageFactory, config) => {
1887
- return () => {
1888
- const baseStorage = storageFactory();
1889
- return {
1890
- ...baseStorage,
1891
- name: `${baseStorage.name}WithCloudFrontSignedUrl`,
1892
- profiles: {
1893
- ...baseStorage.profiles,
1894
- runtime: {
1895
- ...baseStorage.profiles.runtime,
1896
- async getDownloadUrl(storageUri, context) {
1897
- const storageUrl = new URL(storageUri);
1898
- if (storageUrl.protocol !== "s3:") return baseStorage.profiles.runtime.getDownloadUrl(storageUri, context);
1899
- const [privateKey, publicBaseUrl] = await Promise.all([resolvePrivateKey(config), resolvePublicBaseUrl(config, context)]);
1900
- const url = new URL(publicBaseUrl);
1901
- url.pathname = storageUrl.pathname;
1902
- url.search = "";
1903
- return { fileUrl: (0, _aws_sdk_cloudfront_signer.getSignedUrl)({
1904
- url: url.toString(),
1905
- keyPairId: config.keyPairId,
1906
- privateKey,
1907
- dateLessThan: new Date(Date.now() + (config.expiresSeconds ?? ONE_YEAR_IN_SECONDS) * 1e3).toISOString()
1908
- }) };
1858
+ //#endregion
1859
+ //#region src/s3Storage.ts
1860
+ const isObjectNotFoundError = (error) => error instanceof Error && (error.name === "NotFound" || error.name === "NoSuchKey");
1861
+ function s3Storage(config) {
1862
+ const { bucketName, basePath, downloadUrlSigningKey, getDownloadUrl: configuredGetDownloadUrl, ...s3Config } = config;
1863
+ const getDownloadUrl = configuredGetDownloadUrl ?? (downloadUrlSigningKey ? (0, _hot_updater_plugin_core.createStorageDownloadUrl)(downloadUrlSigningKey) : void 0);
1864
+ const client = new _aws_sdk_client_s3.S3Client(applyS3RuntimeAwsConfig(s3Config));
1865
+ const normalizedBasePath = basePath?.replace(/^\/+|\/+$/g, "") ?? "";
1866
+ const getStorageKey = (0, _hot_updater_plugin_core.createStorageKeyBuilder)(normalizedBasePath);
1867
+ const getListPrefix = (prefix = "") => {
1868
+ const value = [normalizedBasePath, prefix.replace(/^\/+|\/+$/g, "")].filter(Boolean).join("/");
1869
+ return value ? `${value}/` : "";
1870
+ };
1871
+ const getRelativeKey = (key) => {
1872
+ if (!normalizedBasePath) return key;
1873
+ const basePrefix = `${normalizedBasePath}/`;
1874
+ return key.startsWith(basePrefix) ? key.slice(basePrefix.length) : key;
1875
+ };
1876
+ const parseAndValidate = (storageUri) => {
1877
+ const parsed = (0, _hot_updater_plugin_core.parseStorageUri)(storageUri, "s3");
1878
+ if (parsed.bucket !== bucketName) throw new Error(`Bucket name mismatch: expected "${bucketName}", but found "${parsed.bucket}".`);
1879
+ return parsed;
1880
+ };
1881
+ return (0, _hot_updater_plugin_core.createStoragePlugin)({
1882
+ name: "s3Storage",
1883
+ protocol: "s3",
1884
+ async listObjects(prefix) {
1885
+ const objects = [];
1886
+ let continuationToken;
1887
+ do {
1888
+ const response = await client.send(new _aws_sdk_client_s3.ListObjectsV2Command({
1889
+ Bucket: bucketName,
1890
+ ContinuationToken: continuationToken,
1891
+ Prefix: getListPrefix(prefix)
1892
+ }));
1893
+ for (const object of response.Contents ?? []) {
1894
+ if (!object.Key) continue;
1895
+ objects.push({
1896
+ key: getRelativeKey(object.Key),
1897
+ lastModifiedAt: object.LastModified,
1898
+ size: object.Size ?? 0,
1899
+ storageUri: `s3://${bucketName}/${object.Key}`
1900
+ });
1901
+ }
1902
+ continuationToken = response.NextContinuationToken;
1903
+ } while (continuationToken);
1904
+ return objects;
1905
+ },
1906
+ async deleteObjects(relativeKeys) {
1907
+ const keys = relativeKeys.map((key) => getStorageKey(key));
1908
+ for (let offset = 0; offset < keys.length; offset += 1e3) {
1909
+ const batch = keys.slice(offset, offset + 1e3);
1910
+ if (batch.length === 0) continue;
1911
+ const response = await client.send(new _aws_sdk_client_s3.DeleteObjectsCommand({
1912
+ Bucket: bucketName,
1913
+ Delete: {
1914
+ Objects: batch.map((Key) => ({ Key })),
1915
+ Quiet: true
1909
1916
  }
1917
+ }));
1918
+ if (response.Errors && response.Errors.length > 0) throw new Error(`Failed to delete ${response.Errors.length} S3 object(s).`);
1919
+ }
1920
+ },
1921
+ async put({ key, body, contentLength, contentType }) {
1922
+ const storageKey = getStorageKey(key);
1923
+ const response = await new _aws_sdk_lib_storage.Upload({
1924
+ client,
1925
+ params: {
1926
+ Body: body,
1927
+ Bucket: bucketName,
1928
+ CacheControl: "max-age=31536000",
1929
+ ...contentLength === void 0 ? {} : { ContentLength: contentLength },
1930
+ ContentType: contentType,
1931
+ Key: storageKey
1910
1932
  }
1933
+ }).done();
1934
+ if (!response.Bucket || !response.Key) throw new Error("Upload failed");
1935
+ return { storageUri: (0, _hot_updater_plugin_core.createStorageUri)({
1936
+ bucket: bucketName,
1937
+ key: storageKey,
1938
+ protocol: "s3"
1939
+ }) };
1940
+ },
1941
+ async get({ storageUri }) {
1942
+ const { key } = parseAndValidate(storageUri);
1943
+ try {
1944
+ const response = await client.send(new _aws_sdk_client_s3.GetObjectCommand({
1945
+ Bucket: bucketName,
1946
+ Key: key
1947
+ }));
1948
+ if (!response.Body) return { response: null };
1949
+ const headers = new Headers();
1950
+ if (response.ContentType) headers.set("content-type", response.ContentType);
1951
+ if (response.ContentLength !== void 0) headers.set("content-length", String(response.ContentLength));
1952
+ return { response: new Response(response.Body.transformToWebStream(), { headers }) };
1953
+ } catch (error) {
1954
+ if (isObjectNotFoundError(error)) return { response: null };
1955
+ throw error;
1911
1956
  }
1912
- };
1913
- };
1914
- };
1915
- //#endregion
1916
- //#region src/s3LambdaEdgeStorage.ts
1917
- const awsLambdaEdgeStorage = (config, hooks) => {
1918
- return withCloudFrontSignedUrl(s3Storage(config, hooks), config);
1919
- };
1920
- const s3LambdaEdgeStorage = awsLambdaEdgeStorage;
1957
+ },
1958
+ ...getDownloadUrl ? { async getDownloadUrl(input) {
1959
+ parseAndValidate(input.storageUri);
1960
+ return getDownloadUrl(input);
1961
+ } } : {},
1962
+ async exists({ storageUri }) {
1963
+ const { key } = parseAndValidate(storageUri);
1964
+ try {
1965
+ await client.send(new _aws_sdk_client_s3.HeadObjectCommand({
1966
+ Bucket: bucketName,
1967
+ Key: key
1968
+ }));
1969
+ return { exists: true };
1970
+ } catch (error) {
1971
+ if (isObjectNotFoundError(error)) return { exists: false };
1972
+ throw error;
1973
+ }
1974
+ },
1975
+ async delete({ storageUri }) {
1976
+ const { key } = parseAndValidate(storageUri);
1977
+ await client.send(new _aws_sdk_client_s3.DeleteObjectCommand({
1978
+ Bucket: bucketName,
1979
+ Key: key
1980
+ }));
1981
+ return { deleted: true };
1982
+ }
1983
+ });
1984
+ }
1921
1985
  //#endregion
1922
- exports.awsLambdaEdgeStorage = awsLambdaEdgeStorage;
1923
- exports.s3Database = s3Database;
1924
- exports.s3LambdaEdgeStorage = s3LambdaEdgeStorage;
1986
+ exports.DYNAMODB_UPDATE_INDEX_NAME = DYNAMODB_UPDATE_INDEX_NAME;
1987
+ exports.cloudFrontDownloadUrl = cloudFrontDownloadUrl;
1988
+ exports.dynamoDB = dynamoDB;
1925
1989
  exports.s3Storage = s3Storage;
1926
- exports.withCloudFrontSignedUrl = withCloudFrontSignedUrl;