@freightos/freightwind 2.1.3 → 2.1.4

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.
@@ -0,0 +1,678 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.VALID_FILE_EXTENSIONS = exports.VALID_MIME_TYPES = void 0;
4
+ exports.normalizeExtension = normalizeExtension;
5
+ exports.hasValidExtension = hasValidExtension;
6
+ exports.validateFileType = validateFileType;
7
+ exports.getMimeTypesForExtension = getMimeTypesForExtension;
8
+ /**
9
+ * MIME-type → extensions map sourced from the IANA / Apache / Nginx MIME database
10
+ * (https://github.com/jshttp/mime-db). Keys are canonical MIME types
11
+ * (e.g. `image/aces`); values are the extensions that legitimately produce that
12
+ * type, without a leading dot and in lowercase.
13
+ *
14
+ * Used to validate uploaded files: reject when the browser-reported `File.type`
15
+ * is unknown, **and** cross-check that the filename's extension matches the set
16
+ * registered for that type. This catches "extension spoofing" — e.g. a `.exe`
17
+ * renamed to `.jpg` will report `application/x-msdownload` (or empty), which
18
+ * does not list `jpg`, so it fails validation.
19
+ */
20
+ exports.VALID_MIME_TYPES = {
21
+ // ── Documents ──────────────────────────────────────────────────────────────
22
+ 'application/pdf': ['pdf'],
23
+ 'application/msword': ['doc', 'dot'],
24
+ 'application/vnd.openxmlformats-officedocument.wordprocessingml.document': ['docx'],
25
+ 'application/vnd.ms-word.document.macroenabled.12': ['docm'],
26
+ 'application/vnd.openxmlformats-officedocument.wordprocessingml.template': ['dotx'],
27
+ 'application/vnd.ms-word.template.macroenabled.12': ['dotm'],
28
+ 'application/vnd.oasis.opendocument.text': ['odt'],
29
+ 'application/vnd.oasis.opendocument.text-template': ['ott'],
30
+ 'application/vnd.oasis.opendocument.text-master': ['odm'],
31
+ 'application/vnd.oasis.opendocument.text-web': ['oth'],
32
+ 'application/rtf': ['rtf'],
33
+ 'text/rtf': ['rtf'],
34
+ 'text/plain': ['txt', 'text', 'conf', 'def', 'list', 'log', 'in', 'ini'],
35
+ 'text/markdown': ['md', 'markdown'],
36
+ 'text/x-markdown': ['mkd'],
37
+ 'text/mdx': ['mdx'],
38
+ 'application/x-tex': ['tex'],
39
+ 'application/x-texinfo': ['texinfo', 'texi'],
40
+ 'application/vnd.wordperfect': ['wpd'],
41
+ 'application/vnd.ms-works': ['wps', 'wks', 'wcm', 'wdb'],
42
+ 'application/vnd.apple.pages': ['pages'],
43
+ 'application/x-iwork-pages-sffpages': ['pages'],
44
+ 'application/vnd.google-apps.document': ['gdoc'],
45
+ 'application/fdf': ['fdf'],
46
+ 'application/vnd.fdf': ['fdf'],
47
+ 'application/xfdf': ['xfdf'],
48
+ 'application/vnd.adobe.xfdf': ['xfdf'],
49
+ 'application/epub+zip': ['epub'],
50
+ 'application/x-mobipocket-ebook': ['mobi', 'prc'],
51
+ 'application/vnd.amazon.ebook': ['azw'],
52
+ 'application/x-abiword': ['abw'],
53
+ 'application/x-gnumeric': ['gnumeric'],
54
+ 'text/richtext': ['rtx'],
55
+ 'text/sgml': ['sgml', 'sgm'],
56
+ 'text/troff': ['t', 'tr', 'roff', 'man', 'me', 'ms'],
57
+ 'application/vnd.software602.filler.form+xml': ['fo'],
58
+ 'text/shex': ['shex'],
59
+ 'text/spdx': ['spdx'],
60
+ 'text/turtle': ['ttl'],
61
+ 'text/n3': ['n3'],
62
+ 'text/vnd.sun.j2me.app-descriptor': ['jad'],
63
+ 'text/x-org': ['org'],
64
+ // ── Spreadsheets ───────────────────────────────────────────────────────────
65
+ 'application/vnd.ms-excel': ['xls', 'xlm', 'xla', 'xlc', 'xlt', 'xlw'],
66
+ 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet': ['xlsx'],
67
+ 'application/vnd.ms-excel.sheet.macroenabled.12': ['xlsm'],
68
+ 'application/vnd.ms-excel.sheet.binary.macroenabled.12': ['xlsb'],
69
+ 'application/vnd.openxmlformats-officedocument.spreadsheetml.template': ['xltx'],
70
+ 'application/vnd.ms-excel.template.macroenabled.12': ['xltm'],
71
+ 'application/vnd.ms-excel.addin.macroenabled.12': ['xlam'],
72
+ 'application/vnd.oasis.opendocument.spreadsheet': ['ods'],
73
+ 'application/vnd.oasis.opendocument.spreadsheet-template': ['ots'],
74
+ 'text/csv': ['csv'],
75
+ 'text/tab-separated-values': ['tsv'],
76
+ 'application/vnd.apple.numbers': ['numbers'],
77
+ 'application/x-iwork-numbers-sffnumbers': ['numbers'],
78
+ 'application/vnd.google-apps.spreadsheet': ['gsheet'],
79
+ // ── Presentations ──────────────────────────────────────────────────────────
80
+ 'application/vnd.ms-powerpoint': ['ppt', 'pps', 'pot'],
81
+ 'application/vnd.openxmlformats-officedocument.presentationml.presentation': ['pptx'],
82
+ 'application/vnd.ms-powerpoint.presentation.macroenabled.12': ['pptm'],
83
+ 'application/vnd.openxmlformats-officedocument.presentationml.slideshow': ['ppsx'],
84
+ 'application/vnd.ms-powerpoint.slideshow.macroenabled.12': ['ppsm'],
85
+ 'application/vnd.openxmlformats-officedocument.presentationml.template': ['potx'],
86
+ 'application/vnd.ms-powerpoint.template.macroenabled.12': ['potm'],
87
+ 'application/vnd.ms-powerpoint.addin.macroenabled.12': ['ppam'],
88
+ 'application/vnd.openxmlformats-officedocument.presentationml.slide': ['sldx'],
89
+ 'application/vnd.ms-powerpoint.slide.macroenabled.12': ['sldm'],
90
+ 'application/vnd.oasis.opendocument.presentation': ['odp'],
91
+ 'application/vnd.oasis.opendocument.presentation-template': ['otp'],
92
+ 'application/vnd.apple.keynote': ['key'],
93
+ 'application/x-iwork-keynote-sffkey': ['key'],
94
+ 'application/vnd.google-apps.presentation': ['gslides'],
95
+ 'application/vnd.google-apps.form': ['gform'],
96
+ 'application/vnd.google-apps.drawing': ['gdraw'],
97
+ 'application/vnd.google-apps.jam': ['gjam'],
98
+ 'application/vnd.google-apps.map': ['gmap'],
99
+ 'application/vnd.google-apps.script': ['gscript'],
100
+ 'application/vnd.google-apps.site': ['gsite'],
101
+ // ── Images ─────────────────────────────────────────────────────────────────
102
+ 'image/png': ['png'],
103
+ 'image/jpeg': ['jpg', 'jpeg', 'jpe'],
104
+ 'image/pjpeg': ['jfif'],
105
+ 'image/gif': ['gif'],
106
+ 'image/webp': ['webp'],
107
+ 'image/avif': ['avif'],
108
+ 'image/apng': ['apng'],
109
+ 'image/bmp': ['bmp', 'dib'],
110
+ 'image/x-ms-bmp': ['bmp'],
111
+ 'image/tiff': ['tif', 'tiff'],
112
+ 'image/svg+xml': ['svg', 'svgz'],
113
+ 'image/x-icon': ['ico'],
114
+ 'image/vnd.microsoft.icon': ['ico'],
115
+ 'image/heic': ['heic'],
116
+ 'image/heic-sequence': ['heics'],
117
+ 'image/heif': ['heif'],
118
+ 'image/heif-sequence': ['heifs'],
119
+ 'image/cgm': ['cgm'],
120
+ 'image/jp2': ['jp2', 'jpg2'],
121
+ 'image/jpx': ['jpx', 'jpf'],
122
+ 'image/jpm': ['jpm', 'jpgm'],
123
+ 'image/jxl': ['jxl'],
124
+ 'image/jxr': ['jxr'],
125
+ 'image/jxra': ['jxra'],
126
+ 'image/jxrs': ['jxrs'],
127
+ 'image/jxs': ['jxs'],
128
+ 'image/jxsc': ['jxsc'],
129
+ 'image/jxsi': ['jxsi'],
130
+ 'image/jxss': ['jxss'],
131
+ 'image/jph': ['jph'],
132
+ 'image/jphc': ['jhc'],
133
+ 'image/hej2k': ['hej2'],
134
+ 'image/jls': ['jls'],
135
+ 'image/jaii': ['jaii'],
136
+ 'image/jais': ['jais'],
137
+ 'image/ktx': ['ktx'],
138
+ 'image/ktx2': ['ktx2'],
139
+ 'image/aces': ['exr'],
140
+ 'image/avci': ['avci'],
141
+ 'image/avcs': ['avcs'],
142
+ 'image/dicom-rle': ['drle'],
143
+ 'image/dpx': ['dpx'],
144
+ 'image/fits': ['fits'],
145
+ 'image/g3fax': ['g3'],
146
+ 'image/ief': ['ief'],
147
+ 'image/t38': ['t38'],
148
+ 'image/tiff-fx': ['tfx'],
149
+ 'image/emf': ['emf'],
150
+ 'image/wmf': ['wmf'],
151
+ 'image/vnd.adobe.photoshop': ['psd'],
152
+ 'application/postscript': ['ai', 'eps', 'ps'],
153
+ 'image/x-adobe-dng': ['dng'],
154
+ 'image/prs.btif': ['btif', 'btf'],
155
+ 'image/prs.pti': ['pti'],
156
+ 'image/vnd.airzip.accelerator.azv': ['azv'],
157
+ 'image/vnd.blockfact.facti': ['facti'],
158
+ 'image/vnd.dece.graphic': ['uvi', 'uvvi', 'uvg', 'uvvg'],
159
+ 'image/vnd.djvu': ['djvu', 'djv'],
160
+ 'image/vnd.dvb.subtitle': ['sub'],
161
+ 'image/vnd.dwg': ['dwg'],
162
+ 'image/vnd.dxf': ['dxf'],
163
+ 'image/vnd.fastbidsheet': ['fbs'],
164
+ 'image/vnd.fpx': ['fpx'],
165
+ 'image/vnd.fst': ['fst'],
166
+ 'image/vnd.fujixerox.edmics-mmr': ['mmr'],
167
+ 'image/vnd.fujixerox.edmics-rlc': ['rlc'],
168
+ 'image/vnd.ms-dds': ['dds'],
169
+ 'image/vnd.ms-modi': ['mdi'],
170
+ 'image/vnd.ms-photo': ['wdp'],
171
+ 'image/vnd.net-fpx': ['npx'],
172
+ 'image/vnd.pco.b16': ['b16'],
173
+ 'image/vnd.tencent.tap': ['tap'],
174
+ 'image/vnd.valve.source.texture': ['vtf'],
175
+ 'image/vnd.wap.wbmp': ['wbmp'],
176
+ 'image/vnd.xiff': ['xif'],
177
+ 'image/vnd.zbrush.pcx': ['pcx'],
178
+ 'image/x-3ds': ['3ds'],
179
+ 'image/x-cmu-raster': ['ras'],
180
+ 'image/x-cmx': ['cmx'],
181
+ 'image/x-freehand': ['fh', 'fhc', 'fh4', 'fh5', 'fh7'],
182
+ 'image/x-jng': ['jng'],
183
+ 'image/x-mrsid-image': ['sid'],
184
+ 'image/sgi': ['sgi'],
185
+ 'image/x-pcx': ['pcx'],
186
+ 'image/x-pict': ['pic', 'pct'],
187
+ 'image/x-portable-anymap': ['pnm'],
188
+ 'image/x-portable-bitmap': ['pbm'],
189
+ 'image/x-portable-graymap': ['pgm'],
190
+ 'image/x-portable-pixmap': ['ppm'],
191
+ 'image/x-rgb': ['rgb'],
192
+ 'image/x-tga': ['tga'],
193
+ 'image/x-xbitmap': ['xbm'],
194
+ 'image/x-xpixmap': ['xpm'],
195
+ 'image/x-xwindowdump': ['xwd'],
196
+ // ── Audio ──────────────────────────────────────────────────────────────────
197
+ 'audio/mpeg': ['mpga', 'mp2', 'mp2a', 'mp3', 'm2a', 'm3a'],
198
+ 'audio/mp3': ['mp3'],
199
+ 'audio/wav': ['wav'],
200
+ 'audio/wave': ['wav'],
201
+ 'audio/x-wav': ['wav'],
202
+ 'audio/ogg': ['oga', 'ogg', 'spx', 'opus'],
203
+ 'audio/mp4': ['m4a', 'mp4a', 'm4b'],
204
+ 'audio/x-m4a': ['m4a'],
205
+ 'audio/aac': ['adts', 'aac'],
206
+ 'audio/x-aac': ['aac'],
207
+ 'audio/x-aiff': ['aif', 'aiff', 'aifc'],
208
+ 'audio/x-flac': ['flac'],
209
+ 'audio/x-ms-wma': ['wma'],
210
+ 'audio/amr': ['amr'],
211
+ 'audio/midi': ['mid', 'midi', 'kar', 'rmi'],
212
+ 'audio/matroska': ['mka'],
213
+ 'audio/x-matroska': ['mka'],
214
+ 'audio/mobile-xmf': ['mxmf'],
215
+ 'audio/basic': ['au', 'snd'],
216
+ 'audio/x-pn-realaudio': ['ram', 'ra'],
217
+ 'audio/x-realaudio': ['ra'],
218
+ 'audio/x-pn-realaudio-plugin': ['rmp'],
219
+ 'audio/webm': ['weba'],
220
+ 'audio/x-caf': ['caf'],
221
+ 'audio/s3m': ['s3m'],
222
+ 'audio/silk': ['sil'],
223
+ 'audio/xm': ['xm'],
224
+ 'audio/x-ms-wax': ['wax'],
225
+ 'audio/x-mpegurl': ['m3u'],
226
+ 'audio/adpcm': ['adp'],
227
+ 'audio/vnd.dra': ['dra'],
228
+ 'audio/vnd.dts': ['dts'],
229
+ 'audio/vnd.dts.hd': ['dtshd'],
230
+ 'audio/vnd.lucent.voice': ['lvp'],
231
+ 'audio/vnd.ms-playready.media.pya': ['pya'],
232
+ 'audio/vnd.digital-winds': ['eol'],
233
+ 'audio/vnd.rip': ['rip'],
234
+ 'audio/vnd.nuera.ecelp4800': ['ecelp4800'],
235
+ 'audio/vnd.nuera.ecelp7470': ['ecelp7470'],
236
+ 'audio/vnd.nuera.ecelp9600': ['ecelp9600'],
237
+ // ── Video ──────────────────────────────────────────────────────────────────
238
+ 'video/mp4': ['mp4', 'mp4v', 'mpg4'],
239
+ 'video/mpeg': ['mpeg', 'mpg', 'mpe', 'm1v', 'm2v'],
240
+ 'video/x-m4v': ['m4v'],
241
+ 'video/quicktime': ['qt', 'mov'],
242
+ 'video/x-msvideo': ['avi'],
243
+ 'video/x-matroska': ['mkv', 'mk3d', 'mks'],
244
+ 'video/matroska': ['mkv'],
245
+ 'video/matroska-3d': ['mk3d'],
246
+ 'video/webm': ['webm'],
247
+ 'video/x-flv': ['flv'],
248
+ 'video/x-f4v': ['f4v'],
249
+ 'video/x-ms-wmv': ['wmv'],
250
+ 'video/x-ms-wm': ['wm'],
251
+ 'video/x-ms-wmx': ['wmx'],
252
+ 'video/x-ms-wvx': ['wvx'],
253
+ 'video/x-ms-asf': ['asf', 'asx'],
254
+ 'video/x-ms-vob': ['vob'],
255
+ 'video/mp2t': ['ts', 'm2t', 'm2ts', 'mts'],
256
+ 'video/ogg': ['ogv'],
257
+ 'video/3gpp': ['3gp', '3gpp'],
258
+ 'video/3gpp2': ['3g2'],
259
+ 'video/vnd.mpegurl': ['mxu', 'm4u'],
260
+ 'video/x-mng': ['mng'],
261
+ 'video/x-fli': ['fli'],
262
+ 'video/x-sgi-movie': ['movie'],
263
+ 'video/x-smv': ['smv'],
264
+ 'video/iso.segment': ['m4s'],
265
+ 'video/mj2': ['mj2', 'mjp2'],
266
+ 'video/h261': ['h261'],
267
+ 'video/h263': ['h263'],
268
+ 'video/h264': ['h264'],
269
+ 'video/jpeg': ['jpgv'],
270
+ 'video/jpm': ['jpm', 'jpgm'],
271
+ 'video/vnd.dvb.file': ['dvb'],
272
+ 'video/vnd.fvt': ['fvt'],
273
+ 'video/vnd.vivo': ['viv'],
274
+ 'video/vnd.ms-playready.media.pyv': ['pyv'],
275
+ 'video/vnd.dece.hd': ['uvh', 'uvvh'],
276
+ 'video/vnd.dece.mobile': ['uvm', 'uvvm'],
277
+ 'video/vnd.dece.pd': ['uvp', 'uvvp'],
278
+ 'video/vnd.dece.sd': ['uvs', 'uvvs'],
279
+ 'video/vnd.dece.video': ['uvv', 'uvvv'],
280
+ 'video/vnd.uvvu.mp4': ['uvu', 'uvvu'],
281
+ // ── Archives & Compression ─────────────────────────────────────────────────
282
+ 'application/zip': ['zip'],
283
+ 'application/x-zip-compressed': ['zip'],
284
+ 'application/vnd.rar': ['rar'],
285
+ 'application/x-rar-compressed': ['rar'],
286
+ 'application/x-compressed': ['rar'],
287
+ 'application/gzip': ['gz'],
288
+ 'application/x-bzip': ['bz'],
289
+ 'application/x-bzip2': ['bz2', 'boz'],
290
+ 'application/x-7z-compressed': ['7z'],
291
+ 'application/x-tar': ['tar'],
292
+ 'application/x-xz': ['xz'],
293
+ 'application/x-lzh-compressed': ['lzh', 'lha'],
294
+ 'application/vnd.ms-cab-compressed': ['cab'],
295
+ 'application/x-arj': ['arj'],
296
+ 'application/x-freearc': ['arc'],
297
+ 'application/x-ace-compressed': ['ace'],
298
+ 'application/x-stuffit': ['sit'],
299
+ 'application/x-stuffitx': ['sitx'],
300
+ 'application/x-sea': ['sea'],
301
+ 'application/x-shar': ['shar'],
302
+ 'application/x-iso9660-image': ['iso'],
303
+ 'application/x-apple-diskimage': ['dmg'],
304
+ 'application/x-cpio': ['cpio'],
305
+ 'application/vnd.android.package-archive': ['apk'],
306
+ 'application/java-archive': ['jar', 'war', 'ear'],
307
+ 'application/x-debian-package': ['deb', 'udeb'],
308
+ 'application/x-redhat-package-manager': ['rpm'],
309
+ 'application/x-msdownload': ['exe', 'dll', 'com', 'bat', 'msi'],
310
+ 'application/octet-stream': ['bin', 'dms', 'lrf', 'mar', 'so', 'dist', 'distz', 'pkg', 'bpk', 'dump', 'elc', 'deploy', 'exe', 'dll', 'deb', 'dmg', 'iso', 'img', 'msi', 'msp', 'msm', 'buffer'],
311
+ 'application/msix': ['msix'],
312
+ 'application/msixbundle': ['msixbundle'],
313
+ 'application/appx': ['appx'],
314
+ 'application/appxbundle': ['appxbundle'],
315
+ 'application/appinstaller': ['appinstaller'],
316
+ 'application/x-chrome-extension': ['crx'],
317
+ 'application/x-xpinstall': ['xpi'],
318
+ 'application/zip+dotlottie': ['lottie'],
319
+ 'application/x-cbr': ['cbr', 'cba', 'cbt', 'cbz', 'cb7'],
320
+ 'application/x-gca-compressed': ['gca'],
321
+ 'application/x-dgc-compressed': ['dgc'],
322
+ 'application/x-virtualbox-ova': ['ova'],
323
+ 'application/x-virtualbox-vbox': ['vbox'],
324
+ 'application/x-virtualbox-vbox-extpack': ['vbox-extpack'],
325
+ 'application/x-sv4cpio': ['sv4cpio'],
326
+ 'application/x-sv4crc': ['sv4crc'],
327
+ 'application/x-ustar': ['ustar'],
328
+ 'application/x-gtar': ['gtar'],
329
+ 'application/x-cfs-compressed': ['cfs'],
330
+ 'application/x-nzb': ['nzb'],
331
+ 'application/x-bittorrent': ['torrent'],
332
+ 'application/vnd.ms-pki.stl': ['stl'],
333
+ // ── Code & Markup ──────────────────────────────────────────────────────────
334
+ 'application/javascript': ['js'],
335
+ 'text/javascript': ['js', 'mjs'],
336
+ 'application/node': ['cjs'],
337
+ 'text/jsx': ['jsx'],
338
+ 'application/json': ['json', 'map'],
339
+ 'application/json5': ['json5'],
340
+ 'application/ld+json': ['jsonld'],
341
+ 'application/jsonml+json': ['jsonml'],
342
+ 'application/wasm': ['wasm'],
343
+ 'text/html': ['html', 'htm', 'shtml'],
344
+ 'application/xhtml+xml': ['xhtml', 'xht'],
345
+ 'text/css': ['css'],
346
+ 'text/less': ['less'],
347
+ 'text/x-sass': ['sass'],
348
+ 'text/x-scss': ['scss'],
349
+ 'text/stylus': ['stylus', 'styl'],
350
+ 'application/xml': ['xml', 'xsl', 'xsd', 'rng'],
351
+ 'text/xml': ['xml'],
352
+ 'application/xslt+xml': ['xsl', 'xslt'],
353
+ 'application/xml-dtd': ['dtd'],
354
+ 'text/x-c': ['c', 'cc', 'cxx', 'cpp', 'h', 'hh', 'dic'],
355
+ 'text/x-java-source': ['java'],
356
+ 'application/java-vm': ['class'],
357
+ 'text/x-php': ['php'],
358
+ 'application/x-httpd-php': ['php'],
359
+ 'text/x-pascal': ['p', 'pas'],
360
+ 'text/x-fortran': ['f', 'for', 'f77', 'f90'],
361
+ 'text/x-asm': ['s', 'asm'],
362
+ 'application/x-perl': ['pl', 'pm'],
363
+ 'application/x-sh': ['sh'],
364
+ 'application/x-csh': ['csh'],
365
+ 'application/x-tcl': ['tcl', 'tk'],
366
+ 'application/x-lua-bytecode': ['luac'],
367
+ 'text/x-lua': ['lua'],
368
+ 'application/x-sql': ['sql'],
369
+ 'application/sql': ['sql'],
370
+ 'application/dart': ['dart'],
371
+ 'application/vnd.dart': ['dart'],
372
+ 'text/coffeescript': ['coffee', 'litcoffee'],
373
+ 'text/jade': ['jade'],
374
+ 'text/x-handlebars-template': ['hbs'],
375
+ 'text/x-processing': ['pde'],
376
+ 'text/mathml': ['mml'],
377
+ 'application/mathml+xml': ['mathml'],
378
+ 'application/yaml': ['yaml', 'yml'],
379
+ 'text/yaml': ['yaml', 'yml'],
380
+ 'application/toml': ['toml'],
381
+ 'text/x-component': ['htc'],
382
+ 'text/x-nfo': ['nfo'],
383
+ 'text/x-opml': ['opml'],
384
+ 'text/uri-list': ['uri', 'uris', 'urls'],
385
+ 'text/x-suse-ymp': ['ymp'],
386
+ 'text/x-uuencode': ['uu'],
387
+ 'text/vnd.curl': ['curl'],
388
+ 'text/vnd.curl.dcurl': ['dcurl'],
389
+ 'text/vnd.curl.mcurl': ['mcurl'],
390
+ 'text/vnd.curl.scurl': ['scurl'],
391
+ 'text/x-sfv': ['sfv'],
392
+ 'text/x-setext': ['etx'],
393
+ 'text/wgsl': ['wgsl'],
394
+ 'application/x-ipynb+json': ['ipynb'],
395
+ 'text/prs.lines.tag': ['dsc'],
396
+ 'text/vnd.fly': ['fly'],
397
+ 'text/vnd.fmi.flexstor': ['flx'],
398
+ 'text/vnd.graphviz': ['gv'],
399
+ 'text/vnd.in3d.3dml': ['3dml'],
400
+ 'text/vnd.in3d.spot': ['spot'],
401
+ 'text/vnd.wap.wml': ['wml'],
402
+ 'text/vnd.wap.wmlscript': ['wmls'],
403
+ // ── Fonts ──────────────────────────────────────────────────────────────────
404
+ 'font/ttf': ['ttf'],
405
+ 'font/otf': ['otf'],
406
+ 'font/collection': ['ttc'],
407
+ 'font/woff': ['woff'],
408
+ 'font/woff2': ['woff2'],
409
+ 'application/vnd.ms-fontobject': ['eot'],
410
+ 'application/x-font-type1': ['pfa', 'pfb', 'pfm', 'afm'],
411
+ 'application/x-font-bdf': ['bdf'],
412
+ 'application/x-font-ghostscript': ['gsf'],
413
+ 'application/x-font-linux-psf': ['psf'],
414
+ 'application/x-font-pcf': ['pcf'],
415
+ 'application/x-font-snf': ['snf'],
416
+ // ── Data & Database ────────────────────────────────────────────────────────
417
+ 'application/vnd.sqlite3': ['sqlite', 'sqlite3'],
418
+ 'application/x-msaccess': ['mdb'],
419
+ 'application/vnd.dbf': ['dbf'],
420
+ 'application/vnd.apache.parquet': ['parquet'],
421
+ 'application/x-netcdf': ['nc', 'cdf'],
422
+ 'application/x-hdf': ['hdf'],
423
+ // ── Office (other) ─────────────────────────────────────────────────────────
424
+ 'application/onenote': ['onetoc', 'onetoc2', 'onetmp', 'onepkg', 'one', 'onea'],
425
+ 'application/x-mspublisher': ['pub'],
426
+ 'application/vnd.ms-project': ['mpp', 'mpt'],
427
+ 'application/vnd.visio': ['vsd', 'vst', 'vss', 'vsw', 'vsdx', 'vtx'],
428
+ 'application/vnd.ms-visio.viewer': ['vdx'],
429
+ 'application/vnd.ms-officetheme': ['thmx'],
430
+ 'application/vnd.ms-htmlhelp': ['chm'],
431
+ 'application/x-msmoney': ['mny'],
432
+ 'application/vnd.ms-wpl': ['wpl'],
433
+ 'application/vnd.ms-xpsdocument': ['xps'],
434
+ 'application/x-msbinder': ['obd'],
435
+ 'application/x-mscardfile': ['crd'],
436
+ 'application/x-msclip': ['clp'],
437
+ 'application/x-msschedule': ['scd'],
438
+ 'application/x-msterminal': ['trm'],
439
+ 'application/x-mswrite': ['wri'],
440
+ 'application/winhlp': ['hlp'],
441
+ // ── CAD & 3D ───────────────────────────────────────────────────────────────
442
+ 'model/vnd.dwf': ['dwf'],
443
+ 'model/step': ['step', 'stp', 'stpnc', 'p21', '210'],
444
+ 'model/step+xml': ['stpx'],
445
+ 'model/step+zip': ['stpz'],
446
+ 'model/step-xml+zip': ['stpxz'],
447
+ 'model/stl': ['stl'],
448
+ 'model/iges': ['iges', 'igs'],
449
+ 'model/3mf': ['3mf'],
450
+ 'model/obj': ['obj'],
451
+ 'model/mtl': ['mtl'],
452
+ 'application/vnd.autodesk.fbx': ['fbx'],
453
+ 'model/gltf+json': ['gltf'],
454
+ 'model/gltf-binary': ['glb'],
455
+ 'model/vnd.usdz+zip': ['usdz'],
456
+ 'model/vnd.usda': ['usda'],
457
+ 'application/x-blender': ['blend'],
458
+ 'model/vnd.collada+xml': ['dae'],
459
+ 'model/x3d+xml': ['x3d', 'x3dz'],
460
+ 'model/x3d+binary': ['x3db', 'x3dbz'],
461
+ 'model/x3d+vrml': ['x3dv', 'x3dvz'],
462
+ 'model/vrml': ['wrl', 'vrml'],
463
+ 'model/mesh': ['msh', 'mesh', 'silo'],
464
+ 'model/u3d': ['u3d'],
465
+ 'model/jt': ['jt'],
466
+ 'model/prc': ['prc'],
467
+ 'model/vnd.bary': ['bary'],
468
+ 'model/vnd.cld': ['cld'],
469
+ 'model/vnd.gdl': ['gdl'],
470
+ 'model/vnd.gtw': ['gtw'],
471
+ 'model/vnd.opengex': ['ogex'],
472
+ 'model/vnd.parasolid.transmit.binary': ['x_b'],
473
+ 'model/vnd.parasolid.transmit.text': ['x_t'],
474
+ 'model/vnd.pytha.pyox': ['pyo', 'pyox'],
475
+ 'model/vnd.sap.vds': ['vds'],
476
+ 'model/vnd.valve.source.compiled-map': ['bsp'],
477
+ 'model/vnd.vtu': ['vtu'],
478
+ // ── Calendar / Contact / Mail ──────────────────────────────────────────────
479
+ 'text/calendar': ['ics', 'ifb'],
480
+ 'text/x-vcalendar': ['vcs'],
481
+ 'text/vcard': ['vcard'],
482
+ 'text/x-vcard': ['vcf'],
483
+ 'message/rfc822': ['eml', 'mime', 'mht', 'mhtml'],
484
+ 'application/vnd.ms-outlook': ['msg'],
485
+ 'application/mbox': ['mbox'],
486
+ 'message/global': ['u8msg'],
487
+ 'message/global-delivery-status': ['u8dsn'],
488
+ 'message/global-disposition-notification': ['u8mdn'],
489
+ 'message/global-headers': ['u8hdr'],
490
+ 'message/vnd.wfa.wsc': ['wsc'],
491
+ 'text/vnd.familysearch.gedcom': ['ged'],
492
+ // ── Certificates / Keys / Crypto ───────────────────────────────────────────
493
+ 'application/x-x509-ca-cert': ['der', 'crt', 'pem'],
494
+ 'application/x-pkcs12': ['p12', 'pfx'],
495
+ 'application/x-pkcs7-certificates': ['p7b', 'spc'],
496
+ 'application/pkcs7-mime': ['p7m', 'p7c'],
497
+ 'application/x-pkcs7-certreqresp': ['p7r'],
498
+ 'application/pkcs7-signature': ['p7s'],
499
+ 'application/pkcs8': ['p8'],
500
+ 'application/pkcs10': ['p10'],
501
+ 'application/pkix-cert': ['cer'],
502
+ 'application/pkix-crl': ['crl'],
503
+ 'application/pkix-pkipath': ['pkipath'],
504
+ 'application/pkixcmp': ['pki'],
505
+ 'application/pgp-encrypted': ['pgp'],
506
+ 'application/pgp-keys': ['asc'],
507
+ 'application/pgp-signature': ['sig', 'asc'],
508
+ 'application/x-keepass2': ['kdbx'],
509
+ // ── Subtitles / Captions ───────────────────────────────────────────────────
510
+ 'application/x-subrip': ['srt'],
511
+ 'text/vtt': ['vtt'],
512
+ 'text/vnd.dvb.subtitle': ['sub'],
513
+ // ── Disk Images / Virtualization ───────────────────────────────────────────
514
+ 'application/x-virtualbox-vhd': ['vhd'],
515
+ 'application/x-virtualbox-vmdk': ['vmdk'],
516
+ 'application/x-virtualbox-vdi': ['vdi'],
517
+ 'application/x-virtualbox-ovf': ['ovf'],
518
+ 'application/x-virtualbox-hdd': ['hdd'],
519
+ // ── GIS / Geospatial ───────────────────────────────────────────────────────
520
+ 'application/geo+json': ['geojson'],
521
+ 'application/vnd.google-earth.kml+xml': ['kml'],
522
+ 'application/vnd.google-earth.kmz': ['kmz'],
523
+ 'application/gpx+xml': ['gpx'],
524
+ 'application/gml+xml': ['gml'],
525
+ 'application/vnd.mapbox-vector-tile': ['mvt'],
526
+ 'application/vnd.openstreetmap.data+xml': ['osm'],
527
+ // ── Web / Manifests / Feeds / RDF ──────────────────────────────────────────
528
+ 'application/manifest+json': ['webmanifest'],
529
+ 'application/x-web-app-manifest+json': ['webapp'],
530
+ 'application/atom+xml': ['atom'],
531
+ 'application/atomcat+xml': ['atomcat'],
532
+ 'application/atomdeleted+xml': ['atomdeleted'],
533
+ 'application/atomsvc+xml': ['atomsvc'],
534
+ 'application/rss+xml': ['rss'],
535
+ 'application/rsd+xml': ['rsd'],
536
+ 'application/rdf+xml': ['rdf', 'owl'],
537
+ 'application/wsdl+xml': ['wsdl'],
538
+ 'application/wspolicy+xml': ['wspolicy'],
539
+ 'application/widget': ['wgt'],
540
+ 'application/yang': ['yang'],
541
+ 'application/yin+xml': ['yin'],
542
+ 'application/xv+xml': ['mxml', 'xhvml', 'xvml', 'xvm'],
543
+ 'application/xaml+xml': ['xaml'],
544
+ 'application/xproc+xml': ['xpl'],
545
+ 'application/xop+xml': ['xop'],
546
+ 'application/xenc+xml': ['xenc'],
547
+ 'application/xliff+xml': ['xlf'],
548
+ 'application/xspf+xml': ['xspf'],
549
+ 'application/vnd.xfdl': ['xfdl'],
550
+ 'application/vnd.xara': ['xar'],
551
+ 'application/voicexml+xml': ['vxml'],
552
+ 'application/watcherinfo+xml': ['wif'],
553
+ // ── Installers / Specialty containers ──────────────────────────────────────
554
+ 'application/x-shockwave-flash': ['swf'],
555
+ 'application/x-silverlight-app': ['xap'],
556
+ 'application/x-ms-application': ['application'],
557
+ 'application/x-ms-shortcut': ['lnk'],
558
+ 'application/x-java-jnlp-file': ['jnlp'],
559
+ 'application/x-install-instructions': ['install'],
560
+ 'application/x-makeself': ['run'],
561
+ 'application/x-java-archive-diff': ['jardiff'],
562
+ 'application/x-mie': ['mie'],
563
+ 'application/vnd.apple.installer+xml': ['mpkg'],
564
+ 'application/vnd.apple.pkpass': ['pkpass'],
565
+ 'application/vnd.apple.mpegurl': ['m3u8'],
566
+ // ── Z-machine / Game data ──────────────────────────────────────────────────
567
+ 'application/x-zmachine': ['z1', 'z2', 'z3', 'z4', 'z5', 'z6', 'z7', 'z8'],
568
+ 'application/x-tads': ['gam'],
569
+ 'application/x-glulx': ['ulx'],
570
+ 'application/x-doom': ['wad'],
571
+ 'application/x-conference': ['nsc'],
572
+ 'application/x-cdlink': ['vcd'],
573
+ 'application/x-chess-pgn': ['pgn'],
574
+ 'application/x-chat': ['chat'],
575
+ 'application/x-cocoa': ['cco'],
576
+ // ── Adobe AIR / Misc app packages ──────────────────────────────────────────
577
+ 'application/vnd.adobe.air-application-installer-package+zip': ['air'],
578
+ 'application/vnd.adobe.fxp': ['fxp', 'fxpl'],
579
+ 'application/vnd.adobe.xdp+xml': ['xdp'],
580
+ 'application/vnd.adobe.formscentral.fcdt': ['fcdt'],
581
+ // ── Other (preserved from prior list) ──────────────────────────────────────
582
+ 'application/x-research-info-systems': ['ris'],
583
+ 'application/x-tex-tfm': ['tfm'],
584
+ 'application/x-t3vm-image': ['t3'],
585
+ 'application/x-eva': ['eva'],
586
+ 'application/x-envoy': ['evy'],
587
+ 'application/x-dvi': ['dvi'],
588
+ 'application/x-dtbresource+xml': ['res'],
589
+ 'application/x-dtbook+xml': ['dtb'],
590
+ 'application/x-dtbncx+xml': ['ncx'],
591
+ 'application/x-director': ['dir', 'dcr', 'dxr', 'cst', 'cct', 'cxt', 'w3d', 'fgd', 'swa'],
592
+ 'application/x-bcpio': ['bcpio'],
593
+ 'application/x-blorb': ['blb', 'blorb'],
594
+ 'application/x-authorware-bin': ['aab', 'x32', 'u32', 'vox'],
595
+ 'application/x-authorware-map': ['aam'],
596
+ 'application/x-authorware-seg': ['aas'],
597
+ 'application/x-futuresplash': ['spl'],
598
+ 'application/x-gramps-xml': ['gramps'],
599
+ 'application/x-wais-source': ['src'],
600
+ 'application/x-pilot': ['prc', 'pdb'],
601
+ 'application/x-pki-message': [],
602
+ 'application/x-ns-proxy-autoconfig': ['pac'],
603
+ 'application/x-xfig': ['fig'],
604
+ 'application/x-msmediaview': ['mvb', 'm13', 'm14'],
605
+ 'application/x-ms-wmd': ['wmd'],
606
+ 'application/x-ms-wmz': ['wmz'],
607
+ 'application/x-ms-xbap': ['xbap'],
608
+ 'application/x-msmetafile': ['wmf', 'wmz', 'emf', 'emz'],
609
+ 'x-conference/x-cooltalk': ['ice'],
610
+ };
611
+ /**
612
+ * Flat set of every extension known to {@link VALID_MIME_TYPES}, used by the
613
+ * extension-only fast path ({@link hasValidExtension}). Derived once at module
614
+ * load — kept in sync with the map automatically.
615
+ */
616
+ exports.VALID_FILE_EXTENSIONS = new Set(Object.values(exports.VALID_MIME_TYPES).flat());
617
+ /**
618
+ * Normalize a filename or raw extension to a lowercase no-dot extension token.
619
+ * Returns null if no extension is present.
620
+ */
621
+ function normalizeExtension(input) {
622
+ const dot = input.lastIndexOf('.');
623
+ if (dot < 0 || dot === input.length - 1)
624
+ return null;
625
+ return input.slice(dot + 1).toLowerCase();
626
+ }
627
+ /**
628
+ * Returns true when the given filename ends in a recognized extension.
629
+ * Files with no extension, or extensions that aren't in {@link VALID_FILE_EXTENSIONS},
630
+ * are rejected as "fake" / nonsense.
631
+ *
632
+ * Prefer {@link validateFileType} when a `File` object is available — it catches
633
+ * extension spoofing that this function cannot.
634
+ */
635
+ function hasValidExtension(filename) {
636
+ const ext = normalizeExtension(filename);
637
+ if (!ext)
638
+ return false;
639
+ return exports.VALID_FILE_EXTENSIONS.has(ext);
640
+ }
641
+ /**
642
+ * Strict file validation: the browser-reported MIME type must be known, AND the
643
+ * filename's extension must be one of the extensions registered for that type.
644
+ *
645
+ * Rejects:
646
+ * - files with no extension
647
+ * - files whose `type` is empty or unknown to {@link VALID_MIME_TYPES}
648
+ * - files whose extension does not match the registered list for `file.type`
649
+ * (extension-spoofing guard, e.g. `.exe` renamed to `.jpg`)
650
+ *
651
+ * `file.type` comparison is case-insensitive; some browsers lowercase but a few
652
+ * legacy ones don't.
653
+ */
654
+ function validateFileType(file) {
655
+ const mimeType = file.type.toLowerCase();
656
+ if (!mimeType)
657
+ return false;
658
+ const allowedExtensions = exports.VALID_MIME_TYPES[mimeType];
659
+ if (!allowedExtensions)
660
+ return false;
661
+ const ext = normalizeExtension(file.name);
662
+ if (!ext)
663
+ return false;
664
+ return allowedExtensions.includes(ext);
665
+ }
666
+ /**
667
+ * Look up every MIME type that legitimately produces the given extension.
668
+ * Useful for `accept`-attribute construction or reverse diagnostics.
669
+ */
670
+ function getMimeTypesForExtension(extension) {
671
+ const ext = extension.startsWith('.') ? extension.slice(1).toLowerCase() : extension.toLowerCase();
672
+ const matches = [];
673
+ for (const [mimeType, exts] of Object.entries(exports.VALID_MIME_TYPES)) {
674
+ if (exts.includes(ext))
675
+ matches.push(mimeType);
676
+ }
677
+ return matches;
678
+ }