@siddharatha/adapter-node-rolldown 1.0.8 → 1.1.3
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/files/env.js +92 -48
- package/files/handler.js +1457 -24
- package/files/index.js +480 -38
- package/files/shims.js +30 -4
- package/index.js +33 -164
- package/package.json +15 -16
- package/files/middlewares.js +0 -162
- package/files/telemetry.js +0 -126
package/files/handler.js
CHANGED
|
@@ -1,27 +1,1460 @@
|
|
|
1
1
|
import 'SHIMS';
|
|
2
|
+
import * as fs from 'node:fs';
|
|
3
|
+
import fs__default, { readdirSync, statSync, createReadStream } from 'node:fs';
|
|
4
|
+
import path, { resolve, join, sep, normalize } from 'node:path';
|
|
5
|
+
import process from 'node:process';
|
|
6
|
+
import * as qs from 'node:querystring';
|
|
7
|
+
import { fileURLToPath } from 'node:url';
|
|
8
|
+
import { Readable } from 'node:stream';
|
|
2
9
|
import { Server } from 'SERVER';
|
|
3
|
-
import { manifest } from 'MANIFEST';
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
10
|
+
import { manifest, prerendered, base } from 'MANIFEST';
|
|
11
|
+
import { env } from 'ENV';
|
|
12
|
+
|
|
13
|
+
function totalist(dir, callback, pre='') {
|
|
14
|
+
dir = resolve('.', dir);
|
|
15
|
+
let arr = readdirSync(dir);
|
|
16
|
+
let i=0, abs, stats;
|
|
17
|
+
for (; i < arr.length; i++) {
|
|
18
|
+
abs = join(dir, arr[i]);
|
|
19
|
+
stats = statSync(abs);
|
|
20
|
+
stats.isDirectory()
|
|
21
|
+
? totalist(abs, callback, join(pre, arr[i]))
|
|
22
|
+
: callback(join(pre, arr[i]), abs, stats);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* @typedef ParsedURL
|
|
28
|
+
* @type {import('.').ParsedURL}
|
|
29
|
+
*/
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* @typedef Request
|
|
33
|
+
* @property {string} url
|
|
34
|
+
* @property {ParsedURL} _parsedUrl
|
|
35
|
+
*/
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* @param {Request} req
|
|
39
|
+
* @returns {ParsedURL|void}
|
|
40
|
+
*/
|
|
41
|
+
function parse(req) {
|
|
42
|
+
let raw = req.url;
|
|
43
|
+
if (raw == null) return;
|
|
44
|
+
|
|
45
|
+
let prev = req._parsedUrl;
|
|
46
|
+
if (prev && prev.raw === raw) return prev;
|
|
47
|
+
|
|
48
|
+
let pathname=raw, search='', query, hash;
|
|
49
|
+
|
|
50
|
+
if (raw.length > 1) {
|
|
51
|
+
let idx = raw.indexOf('#', 1);
|
|
52
|
+
|
|
53
|
+
if (idx !== -1) {
|
|
54
|
+
hash = raw.substring(idx);
|
|
55
|
+
pathname = raw.substring(0, idx);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
idx = pathname.indexOf('?', 1);
|
|
59
|
+
|
|
60
|
+
if (idx !== -1) {
|
|
61
|
+
search = pathname.substring(idx);
|
|
62
|
+
pathname = pathname.substring(0, idx);
|
|
63
|
+
if (search.length > 1) {
|
|
64
|
+
query = qs.parse(search.substring(1));
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
return req._parsedUrl = { pathname, search, query, hash, raw };
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
const mimes = {
|
|
73
|
+
"3g2": "video/3gpp2",
|
|
74
|
+
"3gp": "video/3gpp",
|
|
75
|
+
"3gpp": "video/3gpp",
|
|
76
|
+
"3mf": "model/3mf",
|
|
77
|
+
"aac": "audio/aac",
|
|
78
|
+
"ac": "application/pkix-attr-cert",
|
|
79
|
+
"adp": "audio/adpcm",
|
|
80
|
+
"adts": "audio/aac",
|
|
81
|
+
"ai": "application/postscript",
|
|
82
|
+
"aml": "application/automationml-aml+xml",
|
|
83
|
+
"amlx": "application/automationml-amlx+zip",
|
|
84
|
+
"amr": "audio/amr",
|
|
85
|
+
"apng": "image/apng",
|
|
86
|
+
"appcache": "text/cache-manifest",
|
|
87
|
+
"appinstaller": "application/appinstaller",
|
|
88
|
+
"appx": "application/appx",
|
|
89
|
+
"appxbundle": "application/appxbundle",
|
|
90
|
+
"asc": "application/pgp-keys",
|
|
91
|
+
"atom": "application/atom+xml",
|
|
92
|
+
"atomcat": "application/atomcat+xml",
|
|
93
|
+
"atomdeleted": "application/atomdeleted+xml",
|
|
94
|
+
"atomsvc": "application/atomsvc+xml",
|
|
95
|
+
"au": "audio/basic",
|
|
96
|
+
"avci": "image/avci",
|
|
97
|
+
"avcs": "image/avcs",
|
|
98
|
+
"avif": "image/avif",
|
|
99
|
+
"aw": "application/applixware",
|
|
100
|
+
"bdoc": "application/bdoc",
|
|
101
|
+
"bin": "application/octet-stream",
|
|
102
|
+
"bmp": "image/bmp",
|
|
103
|
+
"bpk": "application/octet-stream",
|
|
104
|
+
"btf": "image/prs.btif",
|
|
105
|
+
"btif": "image/prs.btif",
|
|
106
|
+
"buffer": "application/octet-stream",
|
|
107
|
+
"ccxml": "application/ccxml+xml",
|
|
108
|
+
"cdfx": "application/cdfx+xml",
|
|
109
|
+
"cdmia": "application/cdmi-capability",
|
|
110
|
+
"cdmic": "application/cdmi-container",
|
|
111
|
+
"cdmid": "application/cdmi-domain",
|
|
112
|
+
"cdmio": "application/cdmi-object",
|
|
113
|
+
"cdmiq": "application/cdmi-queue",
|
|
114
|
+
"cer": "application/pkix-cert",
|
|
115
|
+
"cgm": "image/cgm",
|
|
116
|
+
"cjs": "application/node",
|
|
117
|
+
"class": "application/java-vm",
|
|
118
|
+
"coffee": "text/coffeescript",
|
|
119
|
+
"conf": "text/plain",
|
|
120
|
+
"cpl": "application/cpl+xml",
|
|
121
|
+
"cpt": "application/mac-compactpro",
|
|
122
|
+
"crl": "application/pkix-crl",
|
|
123
|
+
"css": "text/css",
|
|
124
|
+
"csv": "text/csv",
|
|
125
|
+
"cu": "application/cu-seeme",
|
|
126
|
+
"cwl": "application/cwl",
|
|
127
|
+
"cww": "application/prs.cww",
|
|
128
|
+
"davmount": "application/davmount+xml",
|
|
129
|
+
"dbk": "application/docbook+xml",
|
|
130
|
+
"deb": "application/octet-stream",
|
|
131
|
+
"def": "text/plain",
|
|
132
|
+
"deploy": "application/octet-stream",
|
|
133
|
+
"dib": "image/bmp",
|
|
134
|
+
"disposition-notification": "message/disposition-notification",
|
|
135
|
+
"dist": "application/octet-stream",
|
|
136
|
+
"distz": "application/octet-stream",
|
|
137
|
+
"dll": "application/octet-stream",
|
|
138
|
+
"dmg": "application/octet-stream",
|
|
139
|
+
"dms": "application/octet-stream",
|
|
140
|
+
"doc": "application/msword",
|
|
141
|
+
"dot": "application/msword",
|
|
142
|
+
"dpx": "image/dpx",
|
|
143
|
+
"drle": "image/dicom-rle",
|
|
144
|
+
"dsc": "text/prs.lines.tag",
|
|
145
|
+
"dssc": "application/dssc+der",
|
|
146
|
+
"dtd": "application/xml-dtd",
|
|
147
|
+
"dump": "application/octet-stream",
|
|
148
|
+
"dwd": "application/atsc-dwd+xml",
|
|
149
|
+
"ear": "application/java-archive",
|
|
150
|
+
"ecma": "application/ecmascript",
|
|
151
|
+
"elc": "application/octet-stream",
|
|
152
|
+
"emf": "image/emf",
|
|
153
|
+
"eml": "message/rfc822",
|
|
154
|
+
"emma": "application/emma+xml",
|
|
155
|
+
"emotionml": "application/emotionml+xml",
|
|
156
|
+
"eps": "application/postscript",
|
|
157
|
+
"epub": "application/epub+zip",
|
|
158
|
+
"exe": "application/octet-stream",
|
|
159
|
+
"exi": "application/exi",
|
|
160
|
+
"exp": "application/express",
|
|
161
|
+
"exr": "image/aces",
|
|
162
|
+
"ez": "application/andrew-inset",
|
|
163
|
+
"fdf": "application/fdf",
|
|
164
|
+
"fdt": "application/fdt+xml",
|
|
165
|
+
"fits": "image/fits",
|
|
166
|
+
"g3": "image/g3fax",
|
|
167
|
+
"gbr": "application/rpki-ghostbusters",
|
|
168
|
+
"geojson": "application/geo+json",
|
|
169
|
+
"gif": "image/gif",
|
|
170
|
+
"glb": "model/gltf-binary",
|
|
171
|
+
"gltf": "model/gltf+json",
|
|
172
|
+
"gml": "application/gml+xml",
|
|
173
|
+
"gpx": "application/gpx+xml",
|
|
174
|
+
"gram": "application/srgs",
|
|
175
|
+
"grxml": "application/srgs+xml",
|
|
176
|
+
"gxf": "application/gxf",
|
|
177
|
+
"gz": "application/gzip",
|
|
178
|
+
"h261": "video/h261",
|
|
179
|
+
"h263": "video/h263",
|
|
180
|
+
"h264": "video/h264",
|
|
181
|
+
"heic": "image/heic",
|
|
182
|
+
"heics": "image/heic-sequence",
|
|
183
|
+
"heif": "image/heif",
|
|
184
|
+
"heifs": "image/heif-sequence",
|
|
185
|
+
"hej2": "image/hej2k",
|
|
186
|
+
"held": "application/atsc-held+xml",
|
|
187
|
+
"hjson": "application/hjson",
|
|
188
|
+
"hlp": "application/winhlp",
|
|
189
|
+
"hqx": "application/mac-binhex40",
|
|
190
|
+
"hsj2": "image/hsj2",
|
|
191
|
+
"htm": "text/html",
|
|
192
|
+
"html": "text/html",
|
|
193
|
+
"ics": "text/calendar",
|
|
194
|
+
"ief": "image/ief",
|
|
195
|
+
"ifb": "text/calendar",
|
|
196
|
+
"iges": "model/iges",
|
|
197
|
+
"igs": "model/iges",
|
|
198
|
+
"img": "application/octet-stream",
|
|
199
|
+
"in": "text/plain",
|
|
200
|
+
"ini": "text/plain",
|
|
201
|
+
"ink": "application/inkml+xml",
|
|
202
|
+
"inkml": "application/inkml+xml",
|
|
203
|
+
"ipfix": "application/ipfix",
|
|
204
|
+
"iso": "application/octet-stream",
|
|
205
|
+
"its": "application/its+xml",
|
|
206
|
+
"jade": "text/jade",
|
|
207
|
+
"jar": "application/java-archive",
|
|
208
|
+
"jhc": "image/jphc",
|
|
209
|
+
"jls": "image/jls",
|
|
210
|
+
"jp2": "image/jp2",
|
|
211
|
+
"jpe": "image/jpeg",
|
|
212
|
+
"jpeg": "image/jpeg",
|
|
213
|
+
"jpf": "image/jpx",
|
|
214
|
+
"jpg": "image/jpeg",
|
|
215
|
+
"jpg2": "image/jp2",
|
|
216
|
+
"jpgm": "image/jpm",
|
|
217
|
+
"jpgv": "video/jpeg",
|
|
218
|
+
"jph": "image/jph",
|
|
219
|
+
"jpm": "image/jpm",
|
|
220
|
+
"jpx": "image/jpx",
|
|
221
|
+
"js": "text/javascript",
|
|
222
|
+
"json": "application/json",
|
|
223
|
+
"json5": "application/json5",
|
|
224
|
+
"jsonld": "application/ld+json",
|
|
225
|
+
"jsonml": "application/jsonml+json",
|
|
226
|
+
"jsx": "text/jsx",
|
|
227
|
+
"jt": "model/jt",
|
|
228
|
+
"jxl": "image/jxl",
|
|
229
|
+
"jxr": "image/jxr",
|
|
230
|
+
"jxra": "image/jxra",
|
|
231
|
+
"jxrs": "image/jxrs",
|
|
232
|
+
"jxs": "image/jxs",
|
|
233
|
+
"jxsc": "image/jxsc",
|
|
234
|
+
"jxsi": "image/jxsi",
|
|
235
|
+
"jxss": "image/jxss",
|
|
236
|
+
"kar": "audio/midi",
|
|
237
|
+
"ktx": "image/ktx",
|
|
238
|
+
"ktx2": "image/ktx2",
|
|
239
|
+
"less": "text/less",
|
|
240
|
+
"lgr": "application/lgr+xml",
|
|
241
|
+
"list": "text/plain",
|
|
242
|
+
"litcoffee": "text/coffeescript",
|
|
243
|
+
"log": "text/plain",
|
|
244
|
+
"lostxml": "application/lost+xml",
|
|
245
|
+
"lrf": "application/octet-stream",
|
|
246
|
+
"m1v": "video/mpeg",
|
|
247
|
+
"m21": "application/mp21",
|
|
248
|
+
"m2a": "audio/mpeg",
|
|
249
|
+
"m2t": "video/mp2t",
|
|
250
|
+
"m2ts": "video/mp2t",
|
|
251
|
+
"m2v": "video/mpeg",
|
|
252
|
+
"m3a": "audio/mpeg",
|
|
253
|
+
"m4a": "audio/mp4",
|
|
254
|
+
"m4p": "application/mp4",
|
|
255
|
+
"m4s": "video/iso.segment",
|
|
256
|
+
"ma": "application/mathematica",
|
|
257
|
+
"mads": "application/mads+xml",
|
|
258
|
+
"maei": "application/mmt-aei+xml",
|
|
259
|
+
"man": "text/troff",
|
|
260
|
+
"manifest": "text/cache-manifest",
|
|
261
|
+
"map": "application/json",
|
|
262
|
+
"mar": "application/octet-stream",
|
|
263
|
+
"markdown": "text/markdown",
|
|
264
|
+
"mathml": "application/mathml+xml",
|
|
265
|
+
"mb": "application/mathematica",
|
|
266
|
+
"mbox": "application/mbox",
|
|
267
|
+
"md": "text/markdown",
|
|
268
|
+
"mdx": "text/mdx",
|
|
269
|
+
"me": "text/troff",
|
|
270
|
+
"mesh": "model/mesh",
|
|
271
|
+
"meta4": "application/metalink4+xml",
|
|
272
|
+
"metalink": "application/metalink+xml",
|
|
273
|
+
"mets": "application/mets+xml",
|
|
274
|
+
"mft": "application/rpki-manifest",
|
|
275
|
+
"mid": "audio/midi",
|
|
276
|
+
"midi": "audio/midi",
|
|
277
|
+
"mime": "message/rfc822",
|
|
278
|
+
"mj2": "video/mj2",
|
|
279
|
+
"mjp2": "video/mj2",
|
|
280
|
+
"mjs": "text/javascript",
|
|
281
|
+
"mml": "text/mathml",
|
|
282
|
+
"mods": "application/mods+xml",
|
|
283
|
+
"mov": "video/quicktime",
|
|
284
|
+
"mp2": "audio/mpeg",
|
|
285
|
+
"mp21": "application/mp21",
|
|
286
|
+
"mp2a": "audio/mpeg",
|
|
287
|
+
"mp3": "audio/mpeg",
|
|
288
|
+
"mp4": "video/mp4",
|
|
289
|
+
"mp4a": "audio/mp4",
|
|
290
|
+
"mp4s": "application/mp4",
|
|
291
|
+
"mp4v": "video/mp4",
|
|
292
|
+
"mpd": "application/dash+xml",
|
|
293
|
+
"mpe": "video/mpeg",
|
|
294
|
+
"mpeg": "video/mpeg",
|
|
295
|
+
"mpf": "application/media-policy-dataset+xml",
|
|
296
|
+
"mpg": "video/mpeg",
|
|
297
|
+
"mpg4": "video/mp4",
|
|
298
|
+
"mpga": "audio/mpeg",
|
|
299
|
+
"mpp": "application/dash-patch+xml",
|
|
300
|
+
"mrc": "application/marc",
|
|
301
|
+
"mrcx": "application/marcxml+xml",
|
|
302
|
+
"ms": "text/troff",
|
|
303
|
+
"mscml": "application/mediaservercontrol+xml",
|
|
304
|
+
"msh": "model/mesh",
|
|
305
|
+
"msi": "application/octet-stream",
|
|
306
|
+
"msix": "application/msix",
|
|
307
|
+
"msixbundle": "application/msixbundle",
|
|
308
|
+
"msm": "application/octet-stream",
|
|
309
|
+
"msp": "application/octet-stream",
|
|
310
|
+
"mtl": "model/mtl",
|
|
311
|
+
"mts": "video/mp2t",
|
|
312
|
+
"musd": "application/mmt-usd+xml",
|
|
313
|
+
"mxf": "application/mxf",
|
|
314
|
+
"mxmf": "audio/mobile-xmf",
|
|
315
|
+
"mxml": "application/xv+xml",
|
|
316
|
+
"n3": "text/n3",
|
|
317
|
+
"nb": "application/mathematica",
|
|
318
|
+
"nq": "application/n-quads",
|
|
319
|
+
"nt": "application/n-triples",
|
|
320
|
+
"obj": "model/obj",
|
|
321
|
+
"oda": "application/oda",
|
|
322
|
+
"oga": "audio/ogg",
|
|
323
|
+
"ogg": "audio/ogg",
|
|
324
|
+
"ogv": "video/ogg",
|
|
325
|
+
"ogx": "application/ogg",
|
|
326
|
+
"omdoc": "application/omdoc+xml",
|
|
327
|
+
"onepkg": "application/onenote",
|
|
328
|
+
"onetmp": "application/onenote",
|
|
329
|
+
"onetoc": "application/onenote",
|
|
330
|
+
"onetoc2": "application/onenote",
|
|
331
|
+
"opf": "application/oebps-package+xml",
|
|
332
|
+
"opus": "audio/ogg",
|
|
333
|
+
"otf": "font/otf",
|
|
334
|
+
"owl": "application/rdf+xml",
|
|
335
|
+
"oxps": "application/oxps",
|
|
336
|
+
"p10": "application/pkcs10",
|
|
337
|
+
"p7c": "application/pkcs7-mime",
|
|
338
|
+
"p7m": "application/pkcs7-mime",
|
|
339
|
+
"p7s": "application/pkcs7-signature",
|
|
340
|
+
"p8": "application/pkcs8",
|
|
341
|
+
"pdf": "application/pdf",
|
|
342
|
+
"pfr": "application/font-tdpfr",
|
|
343
|
+
"pgp": "application/pgp-encrypted",
|
|
344
|
+
"pkg": "application/octet-stream",
|
|
345
|
+
"pki": "application/pkixcmp",
|
|
346
|
+
"pkipath": "application/pkix-pkipath",
|
|
347
|
+
"pls": "application/pls+xml",
|
|
348
|
+
"png": "image/png",
|
|
349
|
+
"prc": "model/prc",
|
|
350
|
+
"prf": "application/pics-rules",
|
|
351
|
+
"provx": "application/provenance+xml",
|
|
352
|
+
"ps": "application/postscript",
|
|
353
|
+
"pskcxml": "application/pskc+xml",
|
|
354
|
+
"pti": "image/prs.pti",
|
|
355
|
+
"qt": "video/quicktime",
|
|
356
|
+
"raml": "application/raml+yaml",
|
|
357
|
+
"rapd": "application/route-apd+xml",
|
|
358
|
+
"rdf": "application/rdf+xml",
|
|
359
|
+
"relo": "application/p2p-overlay+xml",
|
|
360
|
+
"rif": "application/reginfo+xml",
|
|
361
|
+
"rl": "application/resource-lists+xml",
|
|
362
|
+
"rld": "application/resource-lists-diff+xml",
|
|
363
|
+
"rmi": "audio/midi",
|
|
364
|
+
"rnc": "application/relax-ng-compact-syntax",
|
|
365
|
+
"rng": "application/xml",
|
|
366
|
+
"roa": "application/rpki-roa",
|
|
367
|
+
"roff": "text/troff",
|
|
368
|
+
"rq": "application/sparql-query",
|
|
369
|
+
"rs": "application/rls-services+xml",
|
|
370
|
+
"rsat": "application/atsc-rsat+xml",
|
|
371
|
+
"rsd": "application/rsd+xml",
|
|
372
|
+
"rsheet": "application/urc-ressheet+xml",
|
|
373
|
+
"rss": "application/rss+xml",
|
|
374
|
+
"rtf": "text/rtf",
|
|
375
|
+
"rtx": "text/richtext",
|
|
376
|
+
"rusd": "application/route-usd+xml",
|
|
377
|
+
"s3m": "audio/s3m",
|
|
378
|
+
"sbml": "application/sbml+xml",
|
|
379
|
+
"scq": "application/scvp-cv-request",
|
|
380
|
+
"scs": "application/scvp-cv-response",
|
|
381
|
+
"sdp": "application/sdp",
|
|
382
|
+
"senmlx": "application/senml+xml",
|
|
383
|
+
"sensmlx": "application/sensml+xml",
|
|
384
|
+
"ser": "application/java-serialized-object",
|
|
385
|
+
"setpay": "application/set-payment-initiation",
|
|
386
|
+
"setreg": "application/set-registration-initiation",
|
|
387
|
+
"sgi": "image/sgi",
|
|
388
|
+
"sgm": "text/sgml",
|
|
389
|
+
"sgml": "text/sgml",
|
|
390
|
+
"shex": "text/shex",
|
|
391
|
+
"shf": "application/shf+xml",
|
|
392
|
+
"shtml": "text/html",
|
|
393
|
+
"sieve": "application/sieve",
|
|
394
|
+
"sig": "application/pgp-signature",
|
|
395
|
+
"sil": "audio/silk",
|
|
396
|
+
"silo": "model/mesh",
|
|
397
|
+
"siv": "application/sieve",
|
|
398
|
+
"slim": "text/slim",
|
|
399
|
+
"slm": "text/slim",
|
|
400
|
+
"sls": "application/route-s-tsid+xml",
|
|
401
|
+
"smi": "application/smil+xml",
|
|
402
|
+
"smil": "application/smil+xml",
|
|
403
|
+
"snd": "audio/basic",
|
|
404
|
+
"so": "application/octet-stream",
|
|
405
|
+
"spdx": "text/spdx",
|
|
406
|
+
"spp": "application/scvp-vp-response",
|
|
407
|
+
"spq": "application/scvp-vp-request",
|
|
408
|
+
"spx": "audio/ogg",
|
|
409
|
+
"sql": "application/sql",
|
|
410
|
+
"sru": "application/sru+xml",
|
|
411
|
+
"srx": "application/sparql-results+xml",
|
|
412
|
+
"ssdl": "application/ssdl+xml",
|
|
413
|
+
"ssml": "application/ssml+xml",
|
|
414
|
+
"stk": "application/hyperstudio",
|
|
415
|
+
"stl": "model/stl",
|
|
416
|
+
"stpx": "model/step+xml",
|
|
417
|
+
"stpxz": "model/step-xml+zip",
|
|
418
|
+
"stpz": "model/step+zip",
|
|
419
|
+
"styl": "text/stylus",
|
|
420
|
+
"stylus": "text/stylus",
|
|
421
|
+
"svg": "image/svg+xml",
|
|
422
|
+
"svgz": "image/svg+xml",
|
|
423
|
+
"swidtag": "application/swid+xml",
|
|
424
|
+
"t": "text/troff",
|
|
425
|
+
"t38": "image/t38",
|
|
426
|
+
"td": "application/urc-targetdesc+xml",
|
|
427
|
+
"tei": "application/tei+xml",
|
|
428
|
+
"teicorpus": "application/tei+xml",
|
|
429
|
+
"text": "text/plain",
|
|
430
|
+
"tfi": "application/thraud+xml",
|
|
431
|
+
"tfx": "image/tiff-fx",
|
|
432
|
+
"tif": "image/tiff",
|
|
433
|
+
"tiff": "image/tiff",
|
|
434
|
+
"toml": "application/toml",
|
|
435
|
+
"tr": "text/troff",
|
|
436
|
+
"trig": "application/trig",
|
|
437
|
+
"ts": "video/mp2t",
|
|
438
|
+
"tsd": "application/timestamped-data",
|
|
439
|
+
"tsv": "text/tab-separated-values",
|
|
440
|
+
"ttc": "font/collection",
|
|
441
|
+
"ttf": "font/ttf",
|
|
442
|
+
"ttl": "text/turtle",
|
|
443
|
+
"ttml": "application/ttml+xml",
|
|
444
|
+
"txt": "text/plain",
|
|
445
|
+
"u3d": "model/u3d",
|
|
446
|
+
"u8dsn": "message/global-delivery-status",
|
|
447
|
+
"u8hdr": "message/global-headers",
|
|
448
|
+
"u8mdn": "message/global-disposition-notification",
|
|
449
|
+
"u8msg": "message/global",
|
|
450
|
+
"ubj": "application/ubjson",
|
|
451
|
+
"uri": "text/uri-list",
|
|
452
|
+
"uris": "text/uri-list",
|
|
453
|
+
"urls": "text/uri-list",
|
|
454
|
+
"vcard": "text/vcard",
|
|
455
|
+
"vrml": "model/vrml",
|
|
456
|
+
"vtt": "text/vtt",
|
|
457
|
+
"vxml": "application/voicexml+xml",
|
|
458
|
+
"war": "application/java-archive",
|
|
459
|
+
"wasm": "application/wasm",
|
|
460
|
+
"wav": "audio/wav",
|
|
461
|
+
"weba": "audio/webm",
|
|
462
|
+
"webm": "video/webm",
|
|
463
|
+
"webmanifest": "application/manifest+json",
|
|
464
|
+
"webp": "image/webp",
|
|
465
|
+
"wgsl": "text/wgsl",
|
|
466
|
+
"wgt": "application/widget",
|
|
467
|
+
"wif": "application/watcherinfo+xml",
|
|
468
|
+
"wmf": "image/wmf",
|
|
469
|
+
"woff": "font/woff",
|
|
470
|
+
"woff2": "font/woff2",
|
|
471
|
+
"wrl": "model/vrml",
|
|
472
|
+
"wsdl": "application/wsdl+xml",
|
|
473
|
+
"wspolicy": "application/wspolicy+xml",
|
|
474
|
+
"x3d": "model/x3d+xml",
|
|
475
|
+
"x3db": "model/x3d+fastinfoset",
|
|
476
|
+
"x3dbz": "model/x3d+binary",
|
|
477
|
+
"x3dv": "model/x3d-vrml",
|
|
478
|
+
"x3dvz": "model/x3d+vrml",
|
|
479
|
+
"x3dz": "model/x3d+xml",
|
|
480
|
+
"xaml": "application/xaml+xml",
|
|
481
|
+
"xav": "application/xcap-att+xml",
|
|
482
|
+
"xca": "application/xcap-caps+xml",
|
|
483
|
+
"xcs": "application/calendar+xml",
|
|
484
|
+
"xdf": "application/xcap-diff+xml",
|
|
485
|
+
"xdssc": "application/dssc+xml",
|
|
486
|
+
"xel": "application/xcap-el+xml",
|
|
487
|
+
"xenc": "application/xenc+xml",
|
|
488
|
+
"xer": "application/patch-ops-error+xml",
|
|
489
|
+
"xfdf": "application/xfdf",
|
|
490
|
+
"xht": "application/xhtml+xml",
|
|
491
|
+
"xhtml": "application/xhtml+xml",
|
|
492
|
+
"xhvml": "application/xv+xml",
|
|
493
|
+
"xlf": "application/xliff+xml",
|
|
494
|
+
"xm": "audio/xm",
|
|
495
|
+
"xml": "text/xml",
|
|
496
|
+
"xns": "application/xcap-ns+xml",
|
|
497
|
+
"xop": "application/xop+xml",
|
|
498
|
+
"xpl": "application/xproc+xml",
|
|
499
|
+
"xsd": "application/xml",
|
|
500
|
+
"xsf": "application/prs.xsf+xml",
|
|
501
|
+
"xsl": "application/xml",
|
|
502
|
+
"xslt": "application/xml",
|
|
503
|
+
"xspf": "application/xspf+xml",
|
|
504
|
+
"xvm": "application/xv+xml",
|
|
505
|
+
"xvml": "application/xv+xml",
|
|
506
|
+
"yaml": "text/yaml",
|
|
507
|
+
"yang": "application/yang",
|
|
508
|
+
"yin": "application/yin+xml",
|
|
509
|
+
"yml": "text/yaml",
|
|
510
|
+
"zip": "application/zip"
|
|
511
|
+
};
|
|
512
|
+
|
|
513
|
+
function lookup(extn) {
|
|
514
|
+
let tmp = ('' + extn).trim().toLowerCase();
|
|
515
|
+
let idx = tmp.lastIndexOf('.');
|
|
516
|
+
return mimes[!~idx ? tmp : tmp.substring(++idx)];
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
const noop = () => {};
|
|
520
|
+
|
|
521
|
+
function isMatch(uri, arr) {
|
|
522
|
+
for (let i=0; i < arr.length; i++) {
|
|
523
|
+
if (arr[i].test(uri)) return true;
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
function toAssume(uri, extns) {
|
|
528
|
+
let i=0, x, len=uri.length - 1;
|
|
529
|
+
if (uri.charCodeAt(len) === 47) {
|
|
530
|
+
uri = uri.substring(0, len);
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
let arr=[], tmp=`${uri}/index`;
|
|
534
|
+
for (; i < extns.length; i++) {
|
|
535
|
+
x = extns[i] ? `.${extns[i]}` : '';
|
|
536
|
+
if (uri) arr.push(uri + x);
|
|
537
|
+
arr.push(tmp + x);
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
return arr;
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
function viaCache(cache, uri, extns) {
|
|
544
|
+
let i=0, data, arr=toAssume(uri, extns);
|
|
545
|
+
for (; i < arr.length; i++) {
|
|
546
|
+
if (data = cache[arr[i]]) return data;
|
|
547
|
+
}
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
function viaLocal(dir, isEtag, uri, extns) {
|
|
551
|
+
let i=0, arr=toAssume(uri, extns);
|
|
552
|
+
let abs, stats, name, headers;
|
|
553
|
+
for (; i < arr.length; i++) {
|
|
554
|
+
abs = normalize(
|
|
555
|
+
join(dir, name=arr[i])
|
|
556
|
+
);
|
|
557
|
+
|
|
558
|
+
if (abs.startsWith(dir) && fs.existsSync(abs)) {
|
|
559
|
+
stats = fs.statSync(abs);
|
|
560
|
+
if (stats.isDirectory()) continue;
|
|
561
|
+
headers = toHeaders(name, stats, isEtag);
|
|
562
|
+
headers['Cache-Control'] = isEtag ? 'no-cache' : 'no-store';
|
|
563
|
+
return { abs, stats, headers };
|
|
564
|
+
}
|
|
565
|
+
}
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
function is404(req, res) {
|
|
569
|
+
return (res.statusCode=404,res.end());
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
function send(req, res, file, stats, headers) {
|
|
573
|
+
let code=200, tmp, opts={};
|
|
574
|
+
headers = { ...headers };
|
|
575
|
+
|
|
576
|
+
for (let key in headers) {
|
|
577
|
+
tmp = res.getHeader(key);
|
|
578
|
+
if (tmp) headers[key] = tmp;
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
if (tmp = res.getHeader('content-type')) {
|
|
582
|
+
headers['Content-Type'] = tmp;
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
if (req.headers.range) {
|
|
586
|
+
code = 206;
|
|
587
|
+
let [x, y] = req.headers.range.replace('bytes=', '').split('-');
|
|
588
|
+
let end = opts.end = parseInt(y, 10) || stats.size - 1;
|
|
589
|
+
let start = opts.start = parseInt(x, 10) || 0;
|
|
590
|
+
|
|
591
|
+
if (end >= stats.size) {
|
|
592
|
+
end = stats.size - 1;
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
if (start >= stats.size) {
|
|
596
|
+
res.setHeader('Content-Range', `bytes */${stats.size}`);
|
|
597
|
+
res.statusCode = 416;
|
|
598
|
+
return res.end();
|
|
599
|
+
}
|
|
600
|
+
|
|
601
|
+
headers['Content-Range'] = `bytes ${start}-${end}/${stats.size}`;
|
|
602
|
+
headers['Content-Length'] = (end - start + 1);
|
|
603
|
+
headers['Accept-Ranges'] = 'bytes';
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
res.writeHead(code, headers);
|
|
607
|
+
fs.createReadStream(file, opts).pipe(res);
|
|
608
|
+
}
|
|
609
|
+
|
|
610
|
+
const ENCODING = {
|
|
611
|
+
'.br': 'br',
|
|
612
|
+
'.gz': 'gzip',
|
|
27
613
|
};
|
|
614
|
+
|
|
615
|
+
function toHeaders(name, stats, isEtag) {
|
|
616
|
+
let enc = ENCODING[name.slice(-3)];
|
|
617
|
+
|
|
618
|
+
let ctype = lookup(name.slice(0, enc && -3)) || '';
|
|
619
|
+
if (ctype === 'text/html') ctype += ';charset=utf-8';
|
|
620
|
+
|
|
621
|
+
let headers = {
|
|
622
|
+
'Content-Length': stats.size,
|
|
623
|
+
'Content-Type': ctype,
|
|
624
|
+
'Last-Modified': stats.mtime.toUTCString(),
|
|
625
|
+
};
|
|
626
|
+
|
|
627
|
+
if (enc) headers['Content-Encoding'] = enc;
|
|
628
|
+
if (isEtag) headers['ETag'] = `W/"${stats.size}-${stats.mtime.getTime()}"`;
|
|
629
|
+
|
|
630
|
+
return headers;
|
|
631
|
+
}
|
|
632
|
+
|
|
633
|
+
function sirv (dir, opts={}) {
|
|
634
|
+
dir = resolve(dir || '.');
|
|
635
|
+
|
|
636
|
+
let isNotFound = opts.onNoMatch || is404;
|
|
637
|
+
let setHeaders = opts.setHeaders || noop;
|
|
638
|
+
|
|
639
|
+
let extensions = opts.extensions || ['html', 'htm'];
|
|
640
|
+
let gzips = opts.gzip && extensions.map(x => `${x}.gz`).concat('gz');
|
|
641
|
+
let brots = opts.brotli && extensions.map(x => `${x}.br`).concat('br');
|
|
642
|
+
|
|
643
|
+
const FILES = {};
|
|
644
|
+
|
|
645
|
+
let fallback = '/';
|
|
646
|
+
let isEtag = !!opts.etag;
|
|
647
|
+
let isSPA = !!opts.single;
|
|
648
|
+
if (typeof opts.single === 'string') {
|
|
649
|
+
let idx = opts.single.lastIndexOf('.');
|
|
650
|
+
fallback += !!~idx ? opts.single.substring(0, idx) : opts.single;
|
|
651
|
+
}
|
|
652
|
+
|
|
653
|
+
let ignores = [];
|
|
654
|
+
if (opts.ignores !== false) {
|
|
655
|
+
ignores.push(/[/]([A-Za-z\s\d~$._-]+\.\w+){1,}$/); // any extn
|
|
656
|
+
if (opts.dotfiles) ignores.push(/\/\.\w/);
|
|
657
|
+
else ignores.push(/\/\.well-known/);
|
|
658
|
+
[].concat(opts.ignores || []).forEach(x => {
|
|
659
|
+
ignores.push(new RegExp(x, 'i'));
|
|
660
|
+
});
|
|
661
|
+
}
|
|
662
|
+
|
|
663
|
+
let cc = opts.maxAge != null && `public,max-age=${opts.maxAge}`;
|
|
664
|
+
if (cc && opts.immutable) cc += ',immutable';
|
|
665
|
+
else if (cc && opts.maxAge === 0) cc += ',must-revalidate';
|
|
666
|
+
|
|
667
|
+
if (!opts.dev) {
|
|
668
|
+
totalist(dir, (name, abs, stats) => {
|
|
669
|
+
if (/\.well-known[\\+\/]/.test(name)) ; // keep
|
|
670
|
+
else if (!opts.dotfiles && /(^\.|[\\+|\/+]\.)/.test(name)) return;
|
|
671
|
+
|
|
672
|
+
let headers = toHeaders(name, stats, isEtag);
|
|
673
|
+
if (cc) headers['Cache-Control'] = cc;
|
|
674
|
+
|
|
675
|
+
FILES['/' + name.normalize().replace(/\\+/g, '/')] = { abs, stats, headers };
|
|
676
|
+
});
|
|
677
|
+
}
|
|
678
|
+
|
|
679
|
+
let lookup = opts.dev ? viaLocal.bind(0, dir + sep, isEtag) : viaCache.bind(0, FILES);
|
|
680
|
+
|
|
681
|
+
return function (req, res, next) {
|
|
682
|
+
let extns = [''];
|
|
683
|
+
let pathname = parse(req).pathname;
|
|
684
|
+
let val = req.headers['accept-encoding'] || '';
|
|
685
|
+
if (gzips && val.includes('gzip')) extns.unshift(...gzips);
|
|
686
|
+
if (brots && /(br|brotli)/i.test(val)) extns.unshift(...brots);
|
|
687
|
+
extns.push(...extensions); // [...br, ...gz, orig, ...exts]
|
|
688
|
+
|
|
689
|
+
if (pathname.indexOf('%') !== -1) {
|
|
690
|
+
try { pathname = decodeURI(pathname); }
|
|
691
|
+
catch (err) { /* malform uri */ }
|
|
692
|
+
}
|
|
693
|
+
|
|
694
|
+
let data = lookup(pathname, extns) || isSPA && !isMatch(pathname, ignores) && lookup(fallback, extns);
|
|
695
|
+
if (!data) return next ? next() : isNotFound(req, res);
|
|
696
|
+
|
|
697
|
+
if (isEtag && req.headers['if-none-match'] === data.headers['ETag']) {
|
|
698
|
+
res.writeHead(304);
|
|
699
|
+
return res.end();
|
|
700
|
+
}
|
|
701
|
+
|
|
702
|
+
if (gzips || brots) {
|
|
703
|
+
res.setHeader('Vary', 'Accept-Encoding');
|
|
704
|
+
}
|
|
705
|
+
|
|
706
|
+
setHeaders(res, pathname, data.stats);
|
|
707
|
+
send(req, res, data.abs, data.stats, data.headers);
|
|
708
|
+
};
|
|
709
|
+
}
|
|
710
|
+
|
|
711
|
+
var setCookie = {exports: {}};
|
|
712
|
+
|
|
713
|
+
var hasRequiredSetCookie;
|
|
714
|
+
|
|
715
|
+
function requireSetCookie () {
|
|
716
|
+
if (hasRequiredSetCookie) return setCookie.exports;
|
|
717
|
+
hasRequiredSetCookie = 1;
|
|
718
|
+
|
|
719
|
+
var defaultParseOptions = {
|
|
720
|
+
decodeValues: true,
|
|
721
|
+
map: false,
|
|
722
|
+
silent: false,
|
|
723
|
+
};
|
|
724
|
+
|
|
725
|
+
function isForbiddenKey(key) {
|
|
726
|
+
return typeof key !== "string" || key in {};
|
|
727
|
+
}
|
|
728
|
+
|
|
729
|
+
function createNullObj() {
|
|
730
|
+
return Object.create(null);
|
|
731
|
+
}
|
|
732
|
+
|
|
733
|
+
function isNonEmptyString(str) {
|
|
734
|
+
return typeof str === "string" && !!str.trim();
|
|
735
|
+
}
|
|
736
|
+
|
|
737
|
+
function parseString(setCookieValue, options) {
|
|
738
|
+
var parts = setCookieValue.split(";").filter(isNonEmptyString);
|
|
739
|
+
|
|
740
|
+
var nameValuePairStr = parts.shift();
|
|
741
|
+
var parsed = parseNameValuePair(nameValuePairStr);
|
|
742
|
+
var name = parsed.name;
|
|
743
|
+
var value = parsed.value;
|
|
744
|
+
|
|
745
|
+
options = options
|
|
746
|
+
? Object.assign({}, defaultParseOptions, options)
|
|
747
|
+
: defaultParseOptions;
|
|
748
|
+
|
|
749
|
+
if (isForbiddenKey(name)) {
|
|
750
|
+
return null;
|
|
751
|
+
}
|
|
752
|
+
|
|
753
|
+
try {
|
|
754
|
+
value = options.decodeValues ? decodeURIComponent(value) : value; // decode cookie value
|
|
755
|
+
} catch (e) {
|
|
756
|
+
console.error(
|
|
757
|
+
"set-cookie-parser: failed to decode cookie value. Set options.decodeValues=false to disable decoding.",
|
|
758
|
+
e
|
|
759
|
+
);
|
|
760
|
+
}
|
|
761
|
+
|
|
762
|
+
var cookie = createNullObj();
|
|
763
|
+
cookie.name = name;
|
|
764
|
+
cookie.value = value;
|
|
765
|
+
|
|
766
|
+
parts.forEach(function (part) {
|
|
767
|
+
var sides = part.split("=");
|
|
768
|
+
var key = sides.shift().trimLeft().toLowerCase();
|
|
769
|
+
if (isForbiddenKey(key)) {
|
|
770
|
+
return;
|
|
771
|
+
}
|
|
772
|
+
var value = sides.join("=");
|
|
773
|
+
if (key === "expires") {
|
|
774
|
+
cookie.expires = new Date(value);
|
|
775
|
+
} else if (key === "max-age") {
|
|
776
|
+
var n = parseInt(value, 10);
|
|
777
|
+
if (!Number.isNaN(n)) cookie.maxAge = n;
|
|
778
|
+
} else if (key === "secure") {
|
|
779
|
+
cookie.secure = true;
|
|
780
|
+
} else if (key === "httponly") {
|
|
781
|
+
cookie.httpOnly = true;
|
|
782
|
+
} else if (key === "samesite") {
|
|
783
|
+
cookie.sameSite = value;
|
|
784
|
+
} else if (key === "partitioned") {
|
|
785
|
+
cookie.partitioned = true;
|
|
786
|
+
} else if (key) {
|
|
787
|
+
cookie[key] = value;
|
|
788
|
+
}
|
|
789
|
+
});
|
|
790
|
+
|
|
791
|
+
return cookie;
|
|
792
|
+
}
|
|
793
|
+
|
|
794
|
+
function parseNameValuePair(nameValuePairStr) {
|
|
795
|
+
// Parses name-value-pair according to rfc6265bis draft
|
|
796
|
+
|
|
797
|
+
var name = "";
|
|
798
|
+
var value = "";
|
|
799
|
+
var nameValueArr = nameValuePairStr.split("=");
|
|
800
|
+
if (nameValueArr.length > 1) {
|
|
801
|
+
name = nameValueArr.shift();
|
|
802
|
+
value = nameValueArr.join("="); // everything after the first =, joined by a "=" if there was more than one part
|
|
803
|
+
} else {
|
|
804
|
+
value = nameValuePairStr;
|
|
805
|
+
}
|
|
806
|
+
|
|
807
|
+
return { name: name, value: value };
|
|
808
|
+
}
|
|
809
|
+
|
|
810
|
+
function parse(input, options) {
|
|
811
|
+
options = options
|
|
812
|
+
? Object.assign({}, defaultParseOptions, options)
|
|
813
|
+
: defaultParseOptions;
|
|
814
|
+
|
|
815
|
+
if (!input) {
|
|
816
|
+
if (!options.map) {
|
|
817
|
+
return [];
|
|
818
|
+
} else {
|
|
819
|
+
return createNullObj();
|
|
820
|
+
}
|
|
821
|
+
}
|
|
822
|
+
|
|
823
|
+
if (input.headers) {
|
|
824
|
+
if (typeof input.headers.getSetCookie === "function") {
|
|
825
|
+
// for fetch responses - they combine headers of the same type in the headers array,
|
|
826
|
+
// but getSetCookie returns an uncombined array
|
|
827
|
+
input = input.headers.getSetCookie();
|
|
828
|
+
} else if (input.headers["set-cookie"]) {
|
|
829
|
+
// fast-path for node.js (which automatically normalizes header names to lower-case)
|
|
830
|
+
input = input.headers["set-cookie"];
|
|
831
|
+
} else {
|
|
832
|
+
// slow-path for other environments - see #25
|
|
833
|
+
var sch =
|
|
834
|
+
input.headers[
|
|
835
|
+
Object.keys(input.headers).find(function (key) {
|
|
836
|
+
return key.toLowerCase() === "set-cookie";
|
|
837
|
+
})
|
|
838
|
+
];
|
|
839
|
+
// warn if called on a request-like object with a cookie header rather than a set-cookie header - see #34, 36
|
|
840
|
+
if (!sch && input.headers.cookie && !options.silent) {
|
|
841
|
+
console.warn(
|
|
842
|
+
"Warning: set-cookie-parser appears to have been called on a request object. It is designed to parse Set-Cookie headers from responses, not Cookie headers from requests. Set the option {silent: true} to suppress this warning."
|
|
843
|
+
);
|
|
844
|
+
}
|
|
845
|
+
input = sch;
|
|
846
|
+
}
|
|
847
|
+
}
|
|
848
|
+
if (!Array.isArray(input)) {
|
|
849
|
+
input = [input];
|
|
850
|
+
}
|
|
851
|
+
|
|
852
|
+
if (!options.map) {
|
|
853
|
+
return input
|
|
854
|
+
.filter(isNonEmptyString)
|
|
855
|
+
.map(function (str) {
|
|
856
|
+
return parseString(str, options);
|
|
857
|
+
})
|
|
858
|
+
.filter(Boolean);
|
|
859
|
+
} else {
|
|
860
|
+
var cookies = createNullObj();
|
|
861
|
+
return input.filter(isNonEmptyString).reduce(function (cookies, str) {
|
|
862
|
+
var cookie = parseString(str, options);
|
|
863
|
+
if (cookie && !isForbiddenKey(cookie.name)) {
|
|
864
|
+
cookies[cookie.name] = cookie;
|
|
865
|
+
}
|
|
866
|
+
return cookies;
|
|
867
|
+
}, cookies);
|
|
868
|
+
}
|
|
869
|
+
}
|
|
870
|
+
|
|
871
|
+
/*
|
|
872
|
+
Set-Cookie header field-values are sometimes comma joined in one string. This splits them without choking on commas
|
|
873
|
+
that are within a single set-cookie field-value, such as in the Expires portion.
|
|
874
|
+
|
|
875
|
+
This is uncommon, but explicitly allowed - see https://tools.ietf.org/html/rfc2616#section-4.2
|
|
876
|
+
Node.js does this for every header *except* set-cookie - see https://github.com/nodejs/node/blob/d5e363b77ebaf1caf67cd7528224b651c86815c1/lib/_http_incoming.js#L128
|
|
877
|
+
React Native's fetch does this for *every* header, including set-cookie.
|
|
878
|
+
|
|
879
|
+
Based on: https://github.com/google/j2objc/commit/16820fdbc8f76ca0c33472810ce0cb03d20efe25
|
|
880
|
+
Credits to: https://github.com/tomball for original and https://github.com/chrusart for JavaScript implementation
|
|
881
|
+
*/
|
|
882
|
+
function splitCookiesString(cookiesString) {
|
|
883
|
+
if (Array.isArray(cookiesString)) {
|
|
884
|
+
return cookiesString;
|
|
885
|
+
}
|
|
886
|
+
if (typeof cookiesString !== "string") {
|
|
887
|
+
return [];
|
|
888
|
+
}
|
|
889
|
+
|
|
890
|
+
var cookiesStrings = [];
|
|
891
|
+
var pos = 0;
|
|
892
|
+
var start;
|
|
893
|
+
var ch;
|
|
894
|
+
var lastComma;
|
|
895
|
+
var nextStart;
|
|
896
|
+
var cookiesSeparatorFound;
|
|
897
|
+
|
|
898
|
+
function skipWhitespace() {
|
|
899
|
+
while (pos < cookiesString.length && /\s/.test(cookiesString.charAt(pos))) {
|
|
900
|
+
pos += 1;
|
|
901
|
+
}
|
|
902
|
+
return pos < cookiesString.length;
|
|
903
|
+
}
|
|
904
|
+
|
|
905
|
+
function notSpecialChar() {
|
|
906
|
+
ch = cookiesString.charAt(pos);
|
|
907
|
+
|
|
908
|
+
return ch !== "=" && ch !== ";" && ch !== ",";
|
|
909
|
+
}
|
|
910
|
+
|
|
911
|
+
while (pos < cookiesString.length) {
|
|
912
|
+
start = pos;
|
|
913
|
+
cookiesSeparatorFound = false;
|
|
914
|
+
|
|
915
|
+
while (skipWhitespace()) {
|
|
916
|
+
ch = cookiesString.charAt(pos);
|
|
917
|
+
if (ch === ",") {
|
|
918
|
+
// ',' is a cookie separator if we have later first '=', not ';' or ','
|
|
919
|
+
lastComma = pos;
|
|
920
|
+
pos += 1;
|
|
921
|
+
|
|
922
|
+
skipWhitespace();
|
|
923
|
+
nextStart = pos;
|
|
924
|
+
|
|
925
|
+
while (pos < cookiesString.length && notSpecialChar()) {
|
|
926
|
+
pos += 1;
|
|
927
|
+
}
|
|
928
|
+
|
|
929
|
+
// currently special character
|
|
930
|
+
if (pos < cookiesString.length && cookiesString.charAt(pos) === "=") {
|
|
931
|
+
// we found cookies separator
|
|
932
|
+
cookiesSeparatorFound = true;
|
|
933
|
+
// pos is inside the next cookie, so back up and return it.
|
|
934
|
+
pos = nextStart;
|
|
935
|
+
cookiesStrings.push(cookiesString.substring(start, lastComma));
|
|
936
|
+
start = pos;
|
|
937
|
+
} else {
|
|
938
|
+
// in param ',' or param separator ';',
|
|
939
|
+
// we continue from that comma
|
|
940
|
+
pos = lastComma + 1;
|
|
941
|
+
}
|
|
942
|
+
} else {
|
|
943
|
+
pos += 1;
|
|
944
|
+
}
|
|
945
|
+
}
|
|
946
|
+
|
|
947
|
+
if (!cookiesSeparatorFound || pos >= cookiesString.length) {
|
|
948
|
+
cookiesStrings.push(cookiesString.substring(start, cookiesString.length));
|
|
949
|
+
}
|
|
950
|
+
}
|
|
951
|
+
|
|
952
|
+
return cookiesStrings;
|
|
953
|
+
}
|
|
954
|
+
|
|
955
|
+
setCookie.exports = parse;
|
|
956
|
+
setCookie.exports.parse = parse;
|
|
957
|
+
setCookie.exports.parseString = parseString;
|
|
958
|
+
setCookie.exports.splitCookiesString = splitCookiesString;
|
|
959
|
+
return setCookie.exports;
|
|
960
|
+
}
|
|
961
|
+
|
|
962
|
+
var setCookieExports = /*@__PURE__*/ requireSetCookie();
|
|
963
|
+
|
|
964
|
+
/** @import { StandardSchemaV1 } from '@standard-schema/spec' */
|
|
965
|
+
|
|
966
|
+
|
|
967
|
+
/**
|
|
968
|
+
* An error that was thrown from within the SvelteKit runtime that is not fatal and doesn't result in a 500, such as a 404.
|
|
969
|
+
* `SvelteKitError` goes through `handleError`.
|
|
970
|
+
* @extends Error
|
|
971
|
+
*/
|
|
972
|
+
class SvelteKitError extends Error {
|
|
973
|
+
/**
|
|
974
|
+
* @param {number} status
|
|
975
|
+
* @param {string} text
|
|
976
|
+
* @param {string} message
|
|
977
|
+
*/
|
|
978
|
+
constructor(status, text, message) {
|
|
979
|
+
super(message);
|
|
980
|
+
this.status = status;
|
|
981
|
+
this.text = text;
|
|
982
|
+
}
|
|
983
|
+
}
|
|
984
|
+
|
|
985
|
+
/**
|
|
986
|
+
* @param {import('http').IncomingMessage} req
|
|
987
|
+
* @param {number} [body_size_limit]
|
|
988
|
+
*/
|
|
989
|
+
function get_raw_body(req, body_size_limit) {
|
|
990
|
+
const h = req.headers;
|
|
991
|
+
|
|
992
|
+
if (!h['content-type']) {
|
|
993
|
+
return null;
|
|
994
|
+
}
|
|
995
|
+
|
|
996
|
+
const content_length = Number(h['content-length']);
|
|
997
|
+
|
|
998
|
+
// check if no request body
|
|
999
|
+
if (
|
|
1000
|
+
(req.httpVersionMajor === 1 && isNaN(content_length) && h['transfer-encoding'] == null) ||
|
|
1001
|
+
content_length === 0
|
|
1002
|
+
) {
|
|
1003
|
+
return null;
|
|
1004
|
+
}
|
|
1005
|
+
|
|
1006
|
+
if (req.destroyed) {
|
|
1007
|
+
const readable = new ReadableStream();
|
|
1008
|
+
void readable.cancel();
|
|
1009
|
+
return readable;
|
|
1010
|
+
}
|
|
1011
|
+
|
|
1012
|
+
let size = 0;
|
|
1013
|
+
let cancelled = false;
|
|
1014
|
+
|
|
1015
|
+
return new ReadableStream({
|
|
1016
|
+
start(controller) {
|
|
1017
|
+
if (body_size_limit !== undefined && content_length > body_size_limit) {
|
|
1018
|
+
let message = `Content-length of ${content_length} exceeds limit of ${body_size_limit} bytes.`;
|
|
1019
|
+
|
|
1020
|
+
if (body_size_limit === 0) {
|
|
1021
|
+
// https://github.com/sveltejs/kit/pull/11589
|
|
1022
|
+
// TODO this exists to aid migration — remove in a future version
|
|
1023
|
+
message += ' To disable body size limits, specify Infinity rather than 0.';
|
|
1024
|
+
}
|
|
1025
|
+
|
|
1026
|
+
const error = new SvelteKitError(413, 'Payload Too Large', message);
|
|
1027
|
+
|
|
1028
|
+
controller.error(error);
|
|
1029
|
+
return;
|
|
1030
|
+
}
|
|
1031
|
+
|
|
1032
|
+
req.on('error', (error) => {
|
|
1033
|
+
cancelled = true;
|
|
1034
|
+
controller.error(error);
|
|
1035
|
+
});
|
|
1036
|
+
|
|
1037
|
+
req.on('end', () => {
|
|
1038
|
+
if (cancelled) return;
|
|
1039
|
+
controller.close();
|
|
1040
|
+
});
|
|
1041
|
+
|
|
1042
|
+
req.on('data', (chunk) => {
|
|
1043
|
+
if (cancelled) return;
|
|
1044
|
+
|
|
1045
|
+
size += chunk.length;
|
|
1046
|
+
if (size > content_length) {
|
|
1047
|
+
cancelled = true;
|
|
1048
|
+
|
|
1049
|
+
const constraint = content_length ? 'content-length' : 'BODY_SIZE_LIMIT';
|
|
1050
|
+
const message = `request body size exceeded ${constraint} of ${content_length}`;
|
|
1051
|
+
|
|
1052
|
+
const error = new SvelteKitError(413, 'Payload Too Large', message);
|
|
1053
|
+
controller.error(error);
|
|
1054
|
+
|
|
1055
|
+
return;
|
|
1056
|
+
}
|
|
1057
|
+
|
|
1058
|
+
controller.enqueue(chunk);
|
|
1059
|
+
|
|
1060
|
+
if (controller.desiredSize === null || controller.desiredSize <= 0) {
|
|
1061
|
+
req.pause();
|
|
1062
|
+
}
|
|
1063
|
+
});
|
|
1064
|
+
},
|
|
1065
|
+
|
|
1066
|
+
pull() {
|
|
1067
|
+
req.resume();
|
|
1068
|
+
},
|
|
1069
|
+
|
|
1070
|
+
cancel(reason) {
|
|
1071
|
+
cancelled = true;
|
|
1072
|
+
req.destroy(reason);
|
|
1073
|
+
}
|
|
1074
|
+
});
|
|
1075
|
+
}
|
|
1076
|
+
|
|
1077
|
+
/**
|
|
1078
|
+
* @param {{
|
|
1079
|
+
* request: import('http').IncomingMessage;
|
|
1080
|
+
* base: string;
|
|
1081
|
+
* bodySizeLimit?: number;
|
|
1082
|
+
* }} options
|
|
1083
|
+
* @returns {Promise<Request>}
|
|
1084
|
+
*/
|
|
1085
|
+
// TODO 3.0 make the signature synchronous?
|
|
1086
|
+
// eslint-disable-next-line @typescript-eslint/require-await
|
|
1087
|
+
async function getRequest({ request, base, bodySizeLimit }) {
|
|
1088
|
+
let headers = /** @type {Record<string, string>} */ (request.headers);
|
|
1089
|
+
if (request.httpVersionMajor >= 2) {
|
|
1090
|
+
// the Request constructor rejects headers with ':' in the name
|
|
1091
|
+
headers = Object.assign({}, headers);
|
|
1092
|
+
// https://www.rfc-editor.org/rfc/rfc9113.html#section-8.3.1-2.3.5
|
|
1093
|
+
if (headers[':authority']) {
|
|
1094
|
+
headers.host = headers[':authority'];
|
|
1095
|
+
}
|
|
1096
|
+
delete headers[':authority'];
|
|
1097
|
+
delete headers[':method'];
|
|
1098
|
+
delete headers[':path'];
|
|
1099
|
+
delete headers[':scheme'];
|
|
1100
|
+
}
|
|
1101
|
+
|
|
1102
|
+
// TODO: Whenever Node >=22 is minimum supported version, we can use `request.readableAborted`
|
|
1103
|
+
// @see https://github.com/nodejs/node/blob/5cf3c3e24c7257a0c6192ed8ef71efec8ddac22b/lib/internal/streams/readable.js#L1443-L1453
|
|
1104
|
+
const controller = new AbortController();
|
|
1105
|
+
let errored = false;
|
|
1106
|
+
let end_emitted = false;
|
|
1107
|
+
request.once('error', () => (errored = true));
|
|
1108
|
+
request.once('end', () => (end_emitted = true));
|
|
1109
|
+
request.once('close', () => {
|
|
1110
|
+
if ((errored || request.destroyed) && !end_emitted) {
|
|
1111
|
+
controller.abort();
|
|
1112
|
+
}
|
|
1113
|
+
});
|
|
1114
|
+
|
|
1115
|
+
return new Request(base + request.url, {
|
|
1116
|
+
// @ts-expect-error
|
|
1117
|
+
duplex: 'half',
|
|
1118
|
+
method: request.method,
|
|
1119
|
+
headers: Object.entries(headers),
|
|
1120
|
+
signal: controller.signal,
|
|
1121
|
+
body:
|
|
1122
|
+
request.method === 'GET' || request.method === 'HEAD'
|
|
1123
|
+
? undefined
|
|
1124
|
+
: get_raw_body(request, bodySizeLimit)
|
|
1125
|
+
});
|
|
1126
|
+
}
|
|
1127
|
+
|
|
1128
|
+
/**
|
|
1129
|
+
* @param {import('http').ServerResponse} res
|
|
1130
|
+
* @param {Response} response
|
|
1131
|
+
* @returns {Promise<void>}
|
|
1132
|
+
*/
|
|
1133
|
+
// TODO 3.0 make the signature synchronous?
|
|
1134
|
+
// eslint-disable-next-line @typescript-eslint/require-await
|
|
1135
|
+
async function setResponse(res, response) {
|
|
1136
|
+
for (const [key, value] of response.headers) {
|
|
1137
|
+
try {
|
|
1138
|
+
res.setHeader(
|
|
1139
|
+
key,
|
|
1140
|
+
key === 'set-cookie'
|
|
1141
|
+
? setCookieExports.splitCookiesString(
|
|
1142
|
+
// This is absurd but necessary, TODO: investigate why
|
|
1143
|
+
/** @type {string}*/ (response.headers.get(key))
|
|
1144
|
+
)
|
|
1145
|
+
: value
|
|
1146
|
+
);
|
|
1147
|
+
} catch (error) {
|
|
1148
|
+
res.getHeaderNames().forEach((name) => res.removeHeader(name));
|
|
1149
|
+
res.writeHead(500).end(String(error));
|
|
1150
|
+
return;
|
|
1151
|
+
}
|
|
1152
|
+
}
|
|
1153
|
+
|
|
1154
|
+
res.writeHead(response.status);
|
|
1155
|
+
|
|
1156
|
+
if (!response.body) {
|
|
1157
|
+
res.end();
|
|
1158
|
+
return;
|
|
1159
|
+
}
|
|
1160
|
+
|
|
1161
|
+
if (response.body.locked) {
|
|
1162
|
+
res.end(
|
|
1163
|
+
'Fatal error: Response body is locked. ' +
|
|
1164
|
+
"This can happen when the response was already read (for example through 'response.json()' or 'response.text()')."
|
|
1165
|
+
);
|
|
1166
|
+
return;
|
|
1167
|
+
}
|
|
1168
|
+
|
|
1169
|
+
const reader = response.body.getReader();
|
|
1170
|
+
|
|
1171
|
+
if (res.destroyed) {
|
|
1172
|
+
void reader.cancel();
|
|
1173
|
+
return;
|
|
1174
|
+
}
|
|
1175
|
+
|
|
1176
|
+
const cancel = (/** @type {Error|undefined} */ error) => {
|
|
1177
|
+
res.off('close', cancel);
|
|
1178
|
+
res.off('error', cancel);
|
|
1179
|
+
|
|
1180
|
+
// If the reader has already been interrupted with an error earlier,
|
|
1181
|
+
// then it will appear here, it is useless, but it needs to be catch.
|
|
1182
|
+
reader.cancel(error).catch(() => {});
|
|
1183
|
+
if (error) res.destroy(error);
|
|
1184
|
+
};
|
|
1185
|
+
|
|
1186
|
+
res.on('close', cancel);
|
|
1187
|
+
res.on('error', cancel);
|
|
1188
|
+
|
|
1189
|
+
void next();
|
|
1190
|
+
async function next() {
|
|
1191
|
+
try {
|
|
1192
|
+
for (;;) {
|
|
1193
|
+
const { done, value } = await reader.read();
|
|
1194
|
+
|
|
1195
|
+
if (done) break;
|
|
1196
|
+
|
|
1197
|
+
if (!res.write(value)) {
|
|
1198
|
+
res.once('drain', next);
|
|
1199
|
+
return;
|
|
1200
|
+
}
|
|
1201
|
+
}
|
|
1202
|
+
res.end();
|
|
1203
|
+
} catch (error) {
|
|
1204
|
+
cancel(error instanceof Error ? error : new Error(String(error)));
|
|
1205
|
+
}
|
|
1206
|
+
}
|
|
1207
|
+
}
|
|
1208
|
+
|
|
1209
|
+
/**
|
|
1210
|
+
* Converts a file on disk to a readable stream
|
|
1211
|
+
* @param {string} file
|
|
1212
|
+
* @returns {ReadableStream}
|
|
1213
|
+
* @since 2.4.0
|
|
1214
|
+
*/
|
|
1215
|
+
function createReadableStream(file) {
|
|
1216
|
+
return /** @type {ReadableStream} */ (Readable.toWeb(createReadStream(file)));
|
|
1217
|
+
}
|
|
1218
|
+
|
|
1219
|
+
/**
|
|
1220
|
+
* Parses the given value into number of bytes.
|
|
1221
|
+
*
|
|
1222
|
+
* @param {string} value - Size in bytes. Can also be specified with a unit suffix kilobytes (K), megabytes (M), or gigabytes (G).
|
|
1223
|
+
* @returns {number}
|
|
1224
|
+
*/
|
|
1225
|
+
function parse_as_bytes(value) {
|
|
1226
|
+
const multiplier =
|
|
1227
|
+
{
|
|
1228
|
+
K: 1024,
|
|
1229
|
+
M: 1024 * 1024,
|
|
1230
|
+
G: 1024 * 1024 * 1024
|
|
1231
|
+
}[value[value.length - 1]?.toUpperCase()] ?? 1;
|
|
1232
|
+
return Number(multiplier != 1 ? value.substring(0, value.length - 1) : value) * multiplier;
|
|
1233
|
+
}
|
|
1234
|
+
|
|
1235
|
+
/* global ENV_PREFIX */
|
|
1236
|
+
/* global PRECOMPRESS */
|
|
1237
|
+
|
|
1238
|
+
const server = new Server(manifest);
|
|
1239
|
+
|
|
1240
|
+
const origin = env('ORIGIN', undefined);
|
|
1241
|
+
const xff_depth = parseInt(env('XFF_DEPTH', '1'));
|
|
1242
|
+
const address_header = env('ADDRESS_HEADER', '').toLowerCase();
|
|
1243
|
+
const protocol_header = env('PROTOCOL_HEADER', '').toLowerCase();
|
|
1244
|
+
const host_header = env('HOST_HEADER', '').toLowerCase();
|
|
1245
|
+
const port_header = env('PORT_HEADER', '').toLowerCase();
|
|
1246
|
+
|
|
1247
|
+
const body_size_limit = parse_as_bytes(env('BODY_SIZE_LIMIT', '512K'));
|
|
1248
|
+
|
|
1249
|
+
if (isNaN(body_size_limit)) {
|
|
1250
|
+
throw new Error(
|
|
1251
|
+
`Invalid BODY_SIZE_LIMIT: '${env('BODY_SIZE_LIMIT')}'. Please provide a numeric value.`
|
|
1252
|
+
);
|
|
1253
|
+
}
|
|
1254
|
+
|
|
1255
|
+
const dir = path.dirname(fileURLToPath(import.meta.url));
|
|
1256
|
+
|
|
1257
|
+
const asset_dir = `${dir}/client${base}`;
|
|
1258
|
+
|
|
1259
|
+
await server.init({
|
|
1260
|
+
env: /** @type {Record<string, string>} */ (process.env),
|
|
1261
|
+
read: (file) => createReadableStream(`${asset_dir}/${file}`)
|
|
1262
|
+
});
|
|
1263
|
+
|
|
1264
|
+
/**
|
|
1265
|
+
* @param {string} path
|
|
1266
|
+
* @param {boolean} client
|
|
1267
|
+
*/
|
|
1268
|
+
function serve(path, client = false) {
|
|
1269
|
+
return fs__default.existsSync(path)
|
|
1270
|
+
? sirv(path, {
|
|
1271
|
+
etag: true,
|
|
1272
|
+
gzip: PRECOMPRESS,
|
|
1273
|
+
brotli: PRECOMPRESS,
|
|
1274
|
+
setHeaders: client
|
|
1275
|
+
? (res, pathname) => {
|
|
1276
|
+
// only apply to build directory, not e.g. version.json
|
|
1277
|
+
if (
|
|
1278
|
+
pathname.startsWith(`/${manifest.appPath}/immutable/`) &&
|
|
1279
|
+
res.statusCode === 200
|
|
1280
|
+
) {
|
|
1281
|
+
res.setHeader('cache-control', 'public,max-age=31536000,immutable');
|
|
1282
|
+
}
|
|
1283
|
+
}
|
|
1284
|
+
: undefined
|
|
1285
|
+
})
|
|
1286
|
+
: undefined;
|
|
1287
|
+
}
|
|
1288
|
+
|
|
1289
|
+
// required because the static file server ignores trailing slashes
|
|
1290
|
+
/** @returns {import('polka').Middleware} */
|
|
1291
|
+
function serve_prerendered() {
|
|
1292
|
+
const handler = serve(path.join(dir, 'prerendered'));
|
|
1293
|
+
|
|
1294
|
+
return (req, res, next) => {
|
|
1295
|
+
let { pathname, search, query } = parse(req);
|
|
1296
|
+
|
|
1297
|
+
try {
|
|
1298
|
+
pathname = decodeURIComponent(pathname);
|
|
1299
|
+
} catch {
|
|
1300
|
+
// ignore invalid URI
|
|
1301
|
+
}
|
|
1302
|
+
|
|
1303
|
+
if (prerendered.has(pathname)) {
|
|
1304
|
+
return handler?.(req, res, next);
|
|
1305
|
+
}
|
|
1306
|
+
|
|
1307
|
+
// remove or add trailing slash as appropriate
|
|
1308
|
+
let location = pathname.at(-1) === '/' ? pathname.slice(0, -1) : pathname + '/';
|
|
1309
|
+
if (prerendered.has(location)) {
|
|
1310
|
+
if (query) location += search;
|
|
1311
|
+
res.writeHead(308, { location }).end();
|
|
1312
|
+
} else {
|
|
1313
|
+
void next();
|
|
1314
|
+
}
|
|
1315
|
+
};
|
|
1316
|
+
}
|
|
1317
|
+
|
|
1318
|
+
/** @type {import('polka').Middleware} */
|
|
1319
|
+
const ssr = async (req, res) => {
|
|
1320
|
+
/** @type {Request} */
|
|
1321
|
+
let request;
|
|
1322
|
+
|
|
1323
|
+
try {
|
|
1324
|
+
request = await getRequest({
|
|
1325
|
+
base: origin || get_origin(req.headers),
|
|
1326
|
+
request: req,
|
|
1327
|
+
bodySizeLimit: body_size_limit
|
|
1328
|
+
});
|
|
1329
|
+
} catch {
|
|
1330
|
+
res.statusCode = 400;
|
|
1331
|
+
res.end('Bad Request');
|
|
1332
|
+
return;
|
|
1333
|
+
}
|
|
1334
|
+
|
|
1335
|
+
await setResponse(
|
|
1336
|
+
res,
|
|
1337
|
+
await server.respond(request, {
|
|
1338
|
+
platform: { req },
|
|
1339
|
+
getClientAddress: () => {
|
|
1340
|
+
if (address_header) {
|
|
1341
|
+
if (!(address_header in req.headers)) {
|
|
1342
|
+
throw new Error(
|
|
1343
|
+
`Address header was specified with ${ENV_PREFIX + 'ADDRESS_HEADER'
|
|
1344
|
+
}=${address_header} but is absent from request`
|
|
1345
|
+
);
|
|
1346
|
+
}
|
|
1347
|
+
|
|
1348
|
+
const value = /** @type {string} */ (req.headers[address_header]) || '';
|
|
1349
|
+
|
|
1350
|
+
if (address_header === 'x-forwarded-for') {
|
|
1351
|
+
const addresses = value.split(',');
|
|
1352
|
+
|
|
1353
|
+
if (xff_depth < 1) {
|
|
1354
|
+
throw new Error(`${ENV_PREFIX + 'XFF_DEPTH'} must be a positive integer`);
|
|
1355
|
+
}
|
|
1356
|
+
|
|
1357
|
+
if (xff_depth > addresses.length) {
|
|
1358
|
+
throw new Error(
|
|
1359
|
+
`${ENV_PREFIX + 'XFF_DEPTH'} is ${xff_depth}, but only found ${addresses.length
|
|
1360
|
+
} addresses`
|
|
1361
|
+
);
|
|
1362
|
+
}
|
|
1363
|
+
return addresses[addresses.length - xff_depth].trim();
|
|
1364
|
+
}
|
|
1365
|
+
|
|
1366
|
+
return value;
|
|
1367
|
+
}
|
|
1368
|
+
|
|
1369
|
+
return (
|
|
1370
|
+
req.connection?.remoteAddress ||
|
|
1371
|
+
// @ts-expect-error
|
|
1372
|
+
req.connection?.socket?.remoteAddress ||
|
|
1373
|
+
req.socket?.remoteAddress ||
|
|
1374
|
+
// @ts-expect-error
|
|
1375
|
+
req.info?.remoteAddress
|
|
1376
|
+
);
|
|
1377
|
+
}
|
|
1378
|
+
})
|
|
1379
|
+
);
|
|
1380
|
+
};
|
|
1381
|
+
|
|
1382
|
+
/** @param {import('polka').Middleware[]} handlers */
|
|
1383
|
+
function sequence(handlers) {
|
|
1384
|
+
/** @type {import('polka').Middleware} */
|
|
1385
|
+
return (req, res, next) => {
|
|
1386
|
+
/**
|
|
1387
|
+
* @param {number} i
|
|
1388
|
+
* @returns {ReturnType<import('polka').Middleware>}
|
|
1389
|
+
*/
|
|
1390
|
+
function handle(i) {
|
|
1391
|
+
if (i < handlers.length) {
|
|
1392
|
+
return handlers[i](req, res, () => handle(i + 1));
|
|
1393
|
+
} else {
|
|
1394
|
+
return next();
|
|
1395
|
+
}
|
|
1396
|
+
}
|
|
1397
|
+
|
|
1398
|
+
return handle(0);
|
|
1399
|
+
};
|
|
1400
|
+
}
|
|
1401
|
+
|
|
1402
|
+
/**
|
|
1403
|
+
* @param {string} name
|
|
1404
|
+
* @param {string | string[] | undefined} value
|
|
1405
|
+
* @returns {string | undefined}
|
|
1406
|
+
*/
|
|
1407
|
+
function normalise_header(name, value) {
|
|
1408
|
+
if (!name) return undefined;
|
|
1409
|
+
if (Array.isArray(value)) {
|
|
1410
|
+
if (value.length === 0) return undefined;
|
|
1411
|
+
if (value.length === 1) return value[0];
|
|
1412
|
+
throw new Error(
|
|
1413
|
+
`Multiple values provided for ${name} header where only one expected: ${value}`
|
|
1414
|
+
);
|
|
1415
|
+
}
|
|
1416
|
+
return value;
|
|
1417
|
+
}
|
|
1418
|
+
|
|
1419
|
+
/**
|
|
1420
|
+
* @param {import('http').IncomingHttpHeaders} headers
|
|
1421
|
+
* @returns {string}
|
|
1422
|
+
*/
|
|
1423
|
+
function get_origin(headers) {
|
|
1424
|
+
const protocol = decodeURIComponent(
|
|
1425
|
+
normalise_header(protocol_header, headers[protocol_header]) || 'https'
|
|
1426
|
+
);
|
|
1427
|
+
|
|
1428
|
+
// this helps us avoid host injections through the protocol header
|
|
1429
|
+
if (protocol.includes(':')) {
|
|
1430
|
+
throw new Error(
|
|
1431
|
+
`The ${protocol_header} header specified ${protocol} which is an invalid because it includes \`:\`. It should only contain the protocol scheme (e.g. \`https\`)`
|
|
1432
|
+
);
|
|
1433
|
+
}
|
|
1434
|
+
|
|
1435
|
+
const host =
|
|
1436
|
+
normalise_header(host_header, headers[host_header]) ||
|
|
1437
|
+
normalise_header('host', headers['host']);
|
|
1438
|
+
if (!host) {
|
|
1439
|
+
const header_names = host_header ? `${host_header} or host headers` : 'host header';
|
|
1440
|
+
throw new Error(
|
|
1441
|
+
`Could not determine host. The request must have a value provided by the ${header_names}`
|
|
1442
|
+
);
|
|
1443
|
+
}
|
|
1444
|
+
|
|
1445
|
+
const port = normalise_header(port_header, headers[port_header]);
|
|
1446
|
+
if (port && isNaN(+port)) {
|
|
1447
|
+
throw new Error(
|
|
1448
|
+
`The ${port_header} header specified ${port} which is an invalid port because it is not a number. The value should only contain the port number (e.g. 443)`
|
|
1449
|
+
);
|
|
1450
|
+
}
|
|
1451
|
+
|
|
1452
|
+
return port ? `${protocol}://${host}:${port}` : `${protocol}://${host}`;
|
|
1453
|
+
}
|
|
1454
|
+
|
|
1455
|
+
const handler = sequence(
|
|
1456
|
+
/** @type {(import('sirv').RequestHandler | import('polka').Middleware)[]} */
|
|
1457
|
+
([serve(path.join(dir, 'client'), true), serve_prerendered(), ssr].filter(Boolean))
|
|
1458
|
+
);
|
|
1459
|
+
|
|
1460
|
+
export { handler };
|