@sveltejs/kit 1.0.0-next.168 → 1.0.0-next.171

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.
@@ -1,382 +1,407 @@
1
- import { m as mkdirp, r as rimraf, d as copy, $, l as logger } from '../cli.js';
2
- import { S as SVELTE_KIT } from './constants.js';
3
- import { readFileSync, writeFileSync } from 'fs';
4
- import { resolve, join, dirname } from 'path';
5
- import { pathToFileURL, resolve as resolve$1, URL } from 'url';
1
+ import * as fs from 'fs';
2
+ import fs__default, { readdirSync, statSync } from 'fs';
3
+ import http from 'http';
4
+ import https from 'https';
5
+ import { resolve, join, normalize } from 'path';
6
+ import * as require$$7 from 'querystring';
7
+ import { s as standard, M as Mime_1 } from './standard.js';
8
+ import { pathToFileURL } from 'url';
9
+ import { getRawBody } from '../node.js';
6
10
  import { __fetch_polyfill } from '../install-fetch.js';
7
- import { g as get_single_valued_header } from './http.js';
8
- import 'sade';
9
- import 'child_process';
10
- import 'net';
11
- import 'os';
12
- import './error.js';
13
- import 'http';
14
- import 'https';
11
+ import { S as SVELTE_KIT, a as SVELTE_KIT_ASSETS } from './constants.js';
15
12
  import 'zlib';
16
13
  import 'stream';
17
14
  import 'util';
18
15
  import 'crypto';
19
16
 
20
17
  /**
21
- * @typedef {import('types/config').PrerenderErrorHandler} PrerenderErrorHandler
22
- * @typedef {import('types/config').PrerenderOnErrorValue} OnError
23
- * @typedef {import('types/internal').Logger} Logger
18
+ * @typedef ParsedURL
19
+ * @type {import('.').ParsedURL}
24
20
  */
25
21
 
26
- /** @param {string} html */
27
- function clean_html(html) {
28
- return html
29
- .replace(/<!\[CDATA\[[\s\S]*?\]\]>/gm, '')
30
- .replace(/(<script[\s\S]*?>)[\s\S]*?<\/script>/gm, '$1</' + 'script>')
31
- .replace(/(<style[\s\S]*?>)[\s\S]*?<\/style>/gm, '$1</' + 'style>')
32
- .replace(/<!--[\s\S]*?-->/gm, '');
33
- }
22
+ /**
23
+ * @typedef Request
24
+ * @property {string} url
25
+ * @property {ParsedURL} _parsedUrl
26
+ */
34
27
 
35
- /** @param {string} attrs */
36
- function get_href(attrs) {
37
- const match = /(?:[\s'"]|^)href\s*=\s*(?:"(.*?)"|'(.*?)'|([^\s>]*))/.exec(attrs);
38
- return match && (match[1] || match[2] || match[3]);
39
- }
28
+ /**
29
+ * @param {Request} req
30
+ * @returns {ParsedURL|void}
31
+ */
32
+ function parse(req) {
33
+ let raw = req.url;
34
+ if (raw == null) return;
40
35
 
41
- /** @param {string} attrs */
42
- function get_src(attrs) {
43
- const match = /(?:[\s'"]|^)src\s*=\s*(?:"(.*?)"|'(.*?)'|([^\s>]*))/.exec(attrs);
44
- return match && (match[1] || match[2] || match[3]);
45
- }
36
+ let prev = req._parsedUrl;
37
+ if (prev && prev.raw === raw) return prev;
46
38
 
47
- /** @param {string} attrs */
48
- function is_rel_external(attrs) {
49
- const match = /rel\s*=\s*(?:["'][^>]*(external)[^>]*["']|(external))/.exec(attrs);
50
- return !!match;
51
- }
39
+ let pathname=raw, search='', query;
40
+
41
+ if (raw.length > 1) {
42
+ let idx = raw.indexOf('?', 1);
52
43
 
53
- /** @param {string} attrs */
54
- function get_srcset_urls(attrs) {
55
- const results = [];
56
- // Note that the srcset allows any ASCII whitespace, including newlines.
57
- const match = /([\s'"]|^)srcset\s*=\s*(?:"(.*?)"|'(.*?)'|([^\s>]*))/s.exec(attrs);
58
- if (match) {
59
- const attr_content = match[1] || match[2] || match[3];
60
- // Parse the content of the srcset attribute.
61
- // The regexp is modelled after the srcset specs (https://html.spec.whatwg.org/multipage/images.html#srcset-attribute)
62
- // and should cover most reasonable cases.
63
- const regex = /\s*([^\s,]\S+[^\s,])\s*((?:\d+w)|(?:-?\d+(?:\.\d+)?(?:[eE]-?\d+)?x))?/gm;
64
- let sub_matches;
65
- while ((sub_matches = regex.exec(attr_content))) {
66
- results.push(sub_matches[1]);
44
+ if (idx !== -1) {
45
+ search = raw.substring(idx);
46
+ pathname = raw.substring(0, idx);
47
+ if (search.length > 1) {
48
+ query = require$$7.parse(search.substring(1));
49
+ }
67
50
  }
68
51
  }
69
- return results;
70
- }
71
52
 
72
- /** @type {(errorDetails: Parameters<PrerenderErrorHandler>[0] ) => string} */
73
- function errorDetailsToString({ status, path, referrer, referenceType }) {
74
- return `${status} ${path}${referrer ? ` (${referenceType} from ${referrer})` : ''}`;
53
+ return req._parsedUrl = { pathname, search, query, raw };
75
54
  }
76
55
 
77
- /** @type {(log: Logger, onError: OnError) => PrerenderErrorHandler} */
78
- function chooseErrorHandler(log, onError) {
79
- switch (onError) {
80
- case 'continue':
81
- return (errorDetails) => {
82
- log.error(errorDetailsToString(errorDetails));
83
- };
84
- case 'fail':
85
- return (errorDetails) => {
86
- throw new Error(errorDetailsToString(errorDetails));
87
- };
88
- default:
89
- return onError;
56
+ function list(dir, callback, pre='') {
57
+ dir = resolve('.', dir);
58
+ let arr = readdirSync(dir);
59
+ let i=0, abs, stats;
60
+ for (; i < arr.length; i++) {
61
+ abs = join(dir, arr[i]);
62
+ stats = statSync(abs);
63
+ stats.isDirectory()
64
+ ? list(abs, callback, join(pre, arr[i]))
65
+ : callback(join(pre, arr[i]), abs, stats);
90
66
  }
91
67
  }
92
68
 
93
- const OK = 2;
94
- const REDIRECT = 3;
95
-
96
- /**
97
- * @param {{
98
- * cwd: string;
99
- * out: string;
100
- * log: Logger;
101
- * config: import('types/config').ValidatedConfig;
102
- * build_data: import('types/internal').BuildData;
103
- * fallback?: string;
104
- * all: boolean; // disregard `export const prerender = true`
105
- * }} opts
106
- */
107
- async function prerender({ cwd, out, log, config, build_data, fallback, all }) {
108
- if (!config.kit.prerender.enabled && !fallback) {
109
- return;
110
- }
69
+ let Mime = Mime_1;
70
+ var lite = new Mime(standard);
111
71
 
112
- __fetch_polyfill();
113
-
114
- const dir = resolve(cwd, `${SVELTE_KIT}/output`);
115
-
116
- const seen = new Set();
72
+ const noop = () => {};
117
73
 
118
- const server_root = resolve(dir);
119
-
120
- /** @type {import('types/app').App} */
121
- const app = await import(pathToFileURL(`${server_root}/server/app.js`).href);
74
+ function isMatch(uri, arr) {
75
+ for (let i=0; i < arr.length; i++) {
76
+ if (arr[i].test(uri)) return true;
77
+ }
78
+ }
122
79
 
123
- app.init({
124
- paths: config.kit.paths,
125
- prerendering: true,
126
- read: (file) => readFileSync(join(config.kit.files.assets, file))
127
- });
80
+ function toAssume(uri, extns) {
81
+ let i=0, x, len=uri.length - 1;
82
+ if (uri.charCodeAt(len) === 47) {
83
+ uri = uri.substring(0, len);
84
+ }
128
85
 
129
- const error = chooseErrorHandler(log, config.kit.prerender.onError);
86
+ let arr=[], tmp=`${uri}/index`;
87
+ for (; i < extns.length; i++) {
88
+ x = extns[i] ? `.${extns[i]}` : '';
89
+ if (uri) arr.push(uri + x);
90
+ arr.push(tmp + x);
91
+ }
130
92
 
131
- const files = new Set([...build_data.static, ...build_data.client]);
93
+ return arr;
94
+ }
132
95
 
133
- build_data.static.forEach((file) => {
134
- if (file.endsWith('/index.html')) {
135
- files.add(file.slice(0, -11));
136
- }
137
- });
96
+ function viaCache(cache, uri, extns) {
97
+ let i=0, data, arr=toAssume(uri, extns);
98
+ for (; i < arr.length; i++) {
99
+ if (data = cache[arr[i]]) return data;
100
+ }
101
+ }
138
102
 
139
- /**
140
- * @param {string} path
141
- */
142
- function normalize(path) {
143
- if (config.kit.trailingSlash === 'always') {
144
- return path.endsWith('/') ? path : `${path}/`;
145
- } else if (config.kit.trailingSlash === 'never') {
146
- return !path.endsWith('/') || path === '/' ? path : path.slice(0, -1);
103
+ function viaLocal(dir, isEtag, uri, extns) {
104
+ let i=0, arr=toAssume(uri, extns);
105
+ let abs, stats, name, headers;
106
+ for (; i < arr.length; i++) {
107
+ abs = normalize(join(dir, name=arr[i]));
108
+ if (abs.startsWith(dir) && fs.existsSync(abs)) {
109
+ stats = fs.statSync(abs);
110
+ if (stats.isDirectory()) continue;
111
+ headers = toHeaders(name, stats, isEtag);
112
+ headers['Cache-Control'] = isEtag ? 'no-cache' : 'no-store';
113
+ return { abs, stats, headers };
147
114
  }
148
-
149
- return path;
150
115
  }
116
+ }
151
117
 
152
- /**
153
- * @param {string} decoded_path
154
- * @param {string?} referrer
155
- */
156
- async function visit(decoded_path, referrer) {
157
- const path = encodeURI(normalize(decoded_path));
158
-
159
- if (seen.has(path)) return;
160
- seen.add(path);
161
-
162
- /** @type {Map<string, import('types/hooks').ServerResponse>} */
163
- const dependencies = new Map();
164
-
165
- const rendered = await app.render(
166
- {
167
- host: config.kit.host,
168
- method: 'GET',
169
- headers: {},
170
- path,
171
- rawBody: null,
172
- query: new URLSearchParams()
173
- },
174
- {
175
- prerender: {
176
- all,
177
- dependencies
178
- }
179
- }
180
- );
181
-
182
- if (rendered) {
183
- const response_type = Math.floor(rendered.status / 100);
184
- const headers = rendered.headers;
185
- const type = headers && headers['content-type'];
186
- const is_html = response_type === REDIRECT || type === 'text/html';
118
+ function is404(req, res) {
119
+ return (res.statusCode=404,res.end());
120
+ }
187
121
 
188
- const parts = decoded_path.split('/');
189
- if (is_html && parts[parts.length - 1] !== 'index.html') {
190
- parts.push('index.html');
191
- }
122
+ function send(req, res, file, stats, headers) {
123
+ let code=200, tmp, opts={};
124
+ headers = { ...headers };
192
125
 
193
- const file = `${out}${parts.join('/')}`;
194
- mkdirp(dirname(file));
126
+ for (let key in headers) {
127
+ tmp = res.getHeader(key);
128
+ if (tmp) headers[key] = tmp;
129
+ }
195
130
 
196
- if (response_type === REDIRECT) {
197
- const location = get_single_valued_header(headers, 'location');
131
+ if (tmp = res.getHeader('content-type')) {
132
+ headers['Content-Type'] = tmp;
133
+ }
198
134
 
199
- if (location) {
200
- log.warn(`${rendered.status} ${decoded_path} -> ${location}`);
201
- writeFileSync(file, `<meta http-equiv="refresh" content="0;url=${encodeURI(location)}">`);
202
- } else {
203
- log.warn(`location header missing on redirect received from ${decoded_path}`);
204
- }
135
+ if (req.headers.range) {
136
+ code = 206;
137
+ let [x, y] = req.headers.range.replace('bytes=', '').split('-');
138
+ let end = opts.end = parseInt(y, 10) || stats.size - 1;
139
+ let start = opts.start = parseInt(x, 10) || 0;
205
140
 
206
- return;
207
- }
141
+ if (start >= stats.size || end >= stats.size) {
142
+ res.setHeader('Content-Range', `bytes */${stats.size}`);
143
+ res.statusCode = 416;
144
+ return res.end();
145
+ }
208
146
 
209
- if (rendered.status === 200) {
210
- log.info(`${rendered.status} ${decoded_path}`);
211
- writeFileSync(file, rendered.body || '');
212
- } else if (response_type !== OK) {
213
- error({ status: rendered.status, path, referrer, referenceType: 'linked' });
214
- }
147
+ headers['Content-Range'] = `bytes ${start}-${end}/${stats.size}`;
148
+ headers['Content-Length'] = (end - start + 1);
149
+ headers['Accept-Ranges'] = 'bytes';
150
+ }
215
151
 
216
- dependencies.forEach((result, dependency_path) => {
217
- const response_type = Math.floor(result.status / 100);
152
+ res.writeHead(code, headers);
153
+ fs.createReadStream(file, opts).pipe(res);
154
+ }
218
155
 
219
- const is_html = result.headers['content-type'] === 'text/html';
156
+ function isEncoding(name, type, headers) {
157
+ headers['Content-Encoding'] = type;
158
+ headers['Content-Type'] = lite.getType(name.replace(/\.([^.]*)$/, '')) || '';
159
+ }
220
160
 
221
- const parts = dependency_path.split('/');
222
- if (is_html && parts[parts.length - 1] !== 'index.html') {
223
- parts.push('index.html');
224
- }
161
+ function toHeaders(name, stats, isEtag) {
162
+ let headers = {
163
+ 'Content-Length': stats.size,
164
+ 'Content-Type': lite.getType(name) || '',
165
+ 'Last-Modified': stats.mtime.toUTCString(),
166
+ };
167
+ if (isEtag) headers['ETag'] = `W/"${stats.size}-${stats.mtime.getTime()}"`;
168
+ if (/\.br$/.test(name)) isEncoding(name, 'br', headers);
169
+ if (/\.gz$/.test(name)) isEncoding(name, 'gzip', headers);
170
+ return headers;
171
+ }
225
172
 
226
- const file = `${out}${parts.join('/')}`;
227
- mkdirp(dirname(file));
173
+ function sirv (dir, opts={}) {
174
+ dir = resolve(dir || '.');
228
175
 
229
- if (result.body) writeFileSync(file, result.body);
176
+ let isNotFound = opts.onNoMatch || is404;
177
+ let setHeaders = opts.setHeaders || noop;
230
178
 
231
- if (response_type === OK) {
232
- log.info(`${result.status} ${dependency_path}`);
233
- } else {
234
- error({
235
- status: result.status,
236
- path: dependency_path,
237
- referrer: path,
238
- referenceType: 'fetched'
239
- });
240
- }
241
- });
179
+ let extensions = opts.extensions || ['html', 'htm'];
180
+ let gzips = opts.gzip && extensions.map(x => `${x}.gz`).concat('gz');
181
+ let brots = opts.brotli && extensions.map(x => `${x}.br`).concat('br');
242
182
 
243
- if (is_html && config.kit.prerender.crawl) {
244
- const cleaned = clean_html(/** @type {string} */ (rendered.body));
183
+ const FILES = {};
245
184
 
246
- let match;
247
- const pattern = /<(a|img|link|source)\s+([\s\S]+?)>/gm;
185
+ let fallback = '/';
186
+ let isEtag = !!opts.etag;
187
+ let isSPA = !!opts.single;
188
+ if (typeof opts.single === 'string') {
189
+ let idx = opts.single.lastIndexOf('.');
190
+ fallback += !!~idx ? opts.single.substring(0, idx) : opts.single;
191
+ }
248
192
 
249
- const hrefs = [];
193
+ let ignores = [];
194
+ if (opts.ignores !== false) {
195
+ ignores.push(/[/]([A-Za-z\s\d~$._-]+\.\w+){1,}$/); // any extn
196
+ if (opts.dotfiles) ignores.push(/\/\.\w/);
197
+ else ignores.push(/\/\.well-known/);
198
+ [].concat(opts.ignores || []).forEach(x => {
199
+ ignores.push(new RegExp(x, 'i'));
200
+ });
201
+ }
250
202
 
251
- while ((match = pattern.exec(cleaned))) {
252
- const element = match[1];
253
- const attrs = match[2];
203
+ let cc = opts.maxAge != null && `public,max-age=${opts.maxAge}`;
204
+ if (cc && opts.immutable) cc += ',immutable';
205
+ else if (cc && opts.maxAge === 0) cc += ',must-revalidate';
254
206
 
255
- if (element === 'a' || element === 'link') {
256
- if (is_rel_external(attrs)) continue;
207
+ if (!opts.dev) {
208
+ list(dir, (name, abs, stats) => {
209
+ if (/\.well-known[\\+\/]/.test(name)) ; // keep
210
+ else if (!opts.dotfiles && /(^\.|[\\+|\/+]\.)/.test(name)) return;
257
211
 
258
- hrefs.push(get_href(attrs));
259
- } else {
260
- if (element === 'img') {
261
- hrefs.push(get_src(attrs));
262
- }
263
- hrefs.push(...get_srcset_urls(attrs));
264
- }
265
- }
212
+ let headers = toHeaders(name, stats, isEtag);
213
+ if (cc) headers['Cache-Control'] = cc;
266
214
 
267
- for (const href of hrefs) {
268
- if (!href) continue;
215
+ FILES['/' + name.normalize().replace(/\\+/g, '/')] = { abs, stats, headers };
216
+ });
217
+ }
269
218
 
270
- const resolved = resolve$1(path, href);
271
- if (!resolved.startsWith('/') || resolved.startsWith('//')) continue;
219
+ let lookup = opts.dev ? viaLocal.bind(0, dir, isEtag) : viaCache.bind(0, FILES);
272
220
 
273
- const parsed = new URL(resolved, 'http://localhost');
274
- const pathname = decodeURI(parsed.pathname);
221
+ return function (req, res, next) {
222
+ let extns = [''];
223
+ let pathname = parse(req).pathname;
224
+ let val = req.headers['accept-encoding'] || '';
225
+ if (gzips && val.includes('gzip')) extns.unshift(...gzips);
226
+ if (brots && /(br|brotli)/i.test(val)) extns.unshift(...brots);
227
+ extns.push(...extensions); // [...br, ...gz, orig, ...exts]
275
228
 
276
- const file = pathname.replace(config.kit.paths.assets, '').slice(1);
277
- if (files.has(file)) continue;
229
+ if (pathname.indexOf('%') !== -1) {
230
+ try { pathname = decodeURIComponent(pathname); }
231
+ catch (err) { /* malform uri */ }
232
+ }
278
233
 
279
- if (parsed.search) ;
234
+ let data = lookup(pathname, extns) || isSPA && !isMatch(pathname, ignores) && lookup(fallback, extns);
235
+ if (!data) return next ? next() : isNotFound(req, res);
280
236
 
281
- await visit(pathname.replace(config.kit.paths.base, ''), path);
282
- }
283
- }
237
+ if (isEtag && req.headers['if-none-match'] === data.headers['ETag']) {
238
+ res.writeHead(304);
239
+ return res.end();
284
240
  }
285
- }
286
241
 
287
- if (config.kit.prerender.enabled) {
288
- for (const entry of config.kit.prerender.entries) {
289
- if (entry === '*') {
290
- for (const entry of build_data.entries) {
291
- await visit(entry, null);
292
- }
293
- } else {
294
- await visit(entry, null);
295
- }
242
+ if (gzips || brots) {
243
+ res.setHeader('Vary', 'Accept-Encoding');
296
244
  }
297
- }
298
245
 
299
- if (fallback) {
300
- const rendered = await app.render(
301
- {
302
- host: config.kit.host,
303
- method: 'GET',
304
- headers: {},
305
- path: '[fallback]', // this doesn't matter, but it's easiest if it's a string
306
- rawBody: null,
307
- query: new URLSearchParams()
308
- },
309
- {
310
- prerender: {
311
- fallback,
312
- all: false
313
- }
314
- }
315
- );
316
-
317
- const file = join(out, fallback);
318
- mkdirp(dirname(file));
319
- writeFileSync(file, rendered.body || '');
320
- }
246
+ setHeaders(res, pathname, data.stats);
247
+ send(req, res, data.abs, data.stats, data.headers);
248
+ };
321
249
  }
322
250
 
251
+ /** @param {string} dir */
252
+ const mutable = (dir) =>
253
+ sirv(dir, {
254
+ etag: true,
255
+ maxAge: 0
256
+ });
257
+
323
258
  /**
324
259
  * @param {{
325
- * cwd: string;
260
+ * port: number;
261
+ * host?: string;
326
262
  * config: import('types/config').ValidatedConfig;
327
- * build_data: import('types/internal').BuildData;
328
- * log: import('types/internal').Logger;
263
+ * https?: boolean;
264
+ * cwd?: string;
329
265
  * }} opts
330
- * @returns {import('types/config').AdapterUtils}
331
266
  */
332
- function get_utils({ cwd, config, build_data, log }) {
333
- return {
334
- log,
335
- rimraf,
336
- mkdirp,
337
- copy,
338
-
339
- copy_client_files(dest) {
340
- copy(`${cwd}/${SVELTE_KIT}/output/client`, dest, (file) => file[0] !== '.');
341
- },
267
+ async function preview({
268
+ port,
269
+ host,
270
+ config,
271
+ https: use_https = false,
272
+ cwd = process.cwd()
273
+ }) {
274
+ __fetch_polyfill();
342
275
 
343
- copy_server_files(dest) {
344
- copy(`${cwd}/${SVELTE_KIT}/output/server`, dest, (file) => file[0] !== '.');
345
- },
276
+ const app_file = resolve(cwd, `${SVELTE_KIT}/output/server/app.js`);
277
+
278
+ /** @type {import('types/app').App} */
279
+ const app = await import(pathToFileURL(app_file).href);
280
+
281
+ /** @type {import('sirv').RequestHandler} */
282
+ const static_handler = fs__default.existsSync(config.kit.files.assets)
283
+ ? mutable(config.kit.files.assets)
284
+ : (_req, _res, next) => {
285
+ if (!next) throw new Error('No next() handler is available');
286
+ return next();
287
+ };
288
+
289
+ const assets_handler = sirv(resolve(cwd, `${SVELTE_KIT}/output/client`), {
290
+ maxAge: 31536000,
291
+ immutable: true
292
+ });
346
293
 
347
- copy_static_files(dest) {
348
- copy(config.kit.files.assets, dest);
294
+ const has_asset_path = !!config.kit.paths.assets;
295
+
296
+ app.init({
297
+ paths: {
298
+ base: config.kit.paths.base,
299
+ assets: has_asset_path ? SVELTE_KIT_ASSETS : config.kit.paths.base
349
300
  },
301
+ prerendering: false,
302
+ read: (file) => fs__default.readFileSync(join(config.kit.files.assets, file))
303
+ });
304
+
305
+ /** @type {import('vite').UserConfig} */
306
+ const vite_config = (config.kit.vite && config.kit.vite()) || {};
307
+
308
+ const server = await get_server(use_https, vite_config, (req, res) => {
309
+ if (req.url == null) {
310
+ throw new Error('Invalid request url');
311
+ }
350
312
 
351
- async prerender({ all = false, dest, fallback }) {
352
- await prerender({
353
- out: dest,
354
- all,
355
- cwd,
356
- config,
357
- build_data,
358
- fallback,
359
- log
313
+ const initial_url = req.url;
314
+
315
+ const render_handler = async () => {
316
+ if (!req.method) throw new Error('Incomplete request');
317
+
318
+ let body;
319
+
320
+ try {
321
+ body = await getRawBody(req);
322
+ } catch (/** @type {any} */ err) {
323
+ res.statusCode = err.status || 400;
324
+ return res.end(err.reason || 'Invalid request body');
325
+ }
326
+
327
+ const parsed = new URL(initial_url, 'http://localhost/');
328
+
329
+ const rendered =
330
+ parsed.pathname.startsWith(config.kit.paths.base) &&
331
+ (await app.render({
332
+ host: /** @type {string} */ (
333
+ config.kit.host || req.headers[config.kit.hostHeader || 'host']
334
+ ),
335
+ method: req.method,
336
+ headers: /** @type {import('types/helper').RequestHeaders} */ (req.headers),
337
+ path: parsed.pathname.replace(config.kit.paths.base, ''),
338
+ query: parsed.searchParams,
339
+ rawBody: body
340
+ }));
341
+
342
+ if (rendered) {
343
+ res.writeHead(rendered.status, rendered.headers);
344
+ if (rendered.body) res.write(rendered.body);
345
+ res.end();
346
+ } else {
347
+ res.statusCode = 404;
348
+ res.end('Not found');
349
+ }
350
+ };
351
+
352
+ if (has_asset_path) {
353
+ if (initial_url.startsWith(SVELTE_KIT_ASSETS)) {
354
+ // custom assets path
355
+ req.url = initial_url.slice(SVELTE_KIT_ASSETS.length);
356
+ assets_handler(req, res, () => {
357
+ static_handler(req, res, render_handler);
358
+ });
359
+ } else {
360
+ render_handler();
361
+ }
362
+ } else {
363
+ if (initial_url.startsWith(config.kit.paths.base)) {
364
+ req.url = initial_url.slice(config.kit.paths.base.length);
365
+ }
366
+ assets_handler(req, res, () => {
367
+ static_handler(req, res, render_handler);
360
368
  });
361
369
  }
362
- };
370
+ });
371
+
372
+ await server.listen(port, host || '0.0.0.0');
373
+
374
+ return Promise.resolve(server);
363
375
  }
364
376
 
365
377
  /**
366
- * @param {import('types/config').ValidatedConfig} config
367
- * @param {import('types/internal').BuildData} build_data
368
- * @param {{ cwd?: string, verbose: boolean }} opts
378
+ * @param {boolean} use_https
379
+ * @param {import('vite').UserConfig} user_config
380
+ * @param {(req: http.IncomingMessage, res: http.ServerResponse) => void} handler
381
+ * @returns {Promise<import('net').Server>}
369
382
  */
370
- async function adapt(config, build_data, { cwd = process.cwd(), verbose }) {
371
- const { name, adapt } = config.kit.adapter;
372
-
373
- console.log($.bold().cyan(`\n> Using ${name}`));
374
-
375
- const log = logger({ verbose });
376
- const utils = get_utils({ cwd, config, build_data, log });
377
- await adapt({ utils, config });
383
+ async function get_server(use_https, user_config, handler) {
384
+ /** @type {https.ServerOptions} */
385
+ const https_options = {};
386
+
387
+ if (use_https) {
388
+ const secure_opts = user_config.server
389
+ ? /** @type {import('tls').SecureContextOptions} */ (user_config.server.https)
390
+ : {};
391
+
392
+ if (secure_opts.key && secure_opts.cert) {
393
+ https_options.key = secure_opts.key.toString();
394
+ https_options.cert = secure_opts.cert.toString();
395
+ } else {
396
+ https_options.key = https_options.cert = (await import('./cert.js')).createCertificate();
397
+ }
398
+ }
378
399
 
379
- log.success('done');
400
+ return Promise.resolve(
401
+ use_https
402
+ ? https.createServer(/** @type {https.ServerOptions} */ (https_options), handler)
403
+ : http.createServer(handler)
404
+ );
380
405
  }
381
406
 
382
- export { adapt };
407
+ export { preview };