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