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