@sveltejs/kit 1.0.0-next.230 → 1.0.0-next.234
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/assets/app/navigation.js +1 -3
- package/assets/client/singletons.js +5 -2
- package/assets/server/index.js +268 -442
- package/dist/chunks/http.js +680 -0
- package/dist/chunks/index.js +303 -445
- package/dist/chunks/index2.js +1 -1
- package/dist/chunks/index3.js +16 -21
- package/dist/chunks/index5.js +33 -42
- package/dist/chunks/index6.js +20 -669
- package/dist/chunks/url.js +1 -23
- package/dist/cli.js +29 -8
- package/dist/hooks.js +8 -8
- package/dist/install-fetch.js +4 -0
- package/dist/node.js +27 -1
- package/package.json +1 -1
- package/types/ambient-modules.d.ts +9 -14
- package/types/app.d.ts +3 -17
- package/types/config.d.ts +0 -6
- package/types/endpoint.d.ts +4 -5
- package/types/helper.d.ts +0 -1
- package/types/hooks.d.ts +15 -28
- package/types/index.d.ts +2 -10
- package/types/internal.d.ts +9 -10
package/dist/chunks/index.js
CHANGED
|
@@ -2,36 +2,46 @@ import path__default from 'path';
|
|
|
2
2
|
import { svelte } from '@sveltejs/vite-plugin-svelte';
|
|
3
3
|
import vite from 'vite';
|
|
4
4
|
import { c as create_manifest_data, a as create_app, d as deep_merge } from './index2.js';
|
|
5
|
-
import { c as coalesce_to_error,
|
|
5
|
+
import { c as coalesce_to_error, S as SVELTE_KIT_ASSETS, r as resolve_entry, $, a as SVELTE_KIT, b as runtime, l as load_template, g as get_mime_lookup, d as copy_assets, e as get_aliases, p as print_config_conflicts } from '../cli.js';
|
|
6
6
|
import fs__default from 'fs';
|
|
7
7
|
import { URL as URL$1 } from 'url';
|
|
8
|
-
import {
|
|
8
|
+
import { t as to_headers, s as sirv } from './http.js';
|
|
9
9
|
import { s } from './misc.js';
|
|
10
|
+
import { r as resolve, i as is_root_relative } from './url.js';
|
|
10
11
|
import { __fetch_polyfill } from '../install-fetch.js';
|
|
11
|
-
import { getRawBody } from '../node.js';
|
|
12
|
+
import { getRawBody, setResponse } from '../node.js';
|
|
12
13
|
import 'sade';
|
|
13
14
|
import 'child_process';
|
|
14
15
|
import 'net';
|
|
15
16
|
import 'os';
|
|
17
|
+
import 'querystring';
|
|
16
18
|
import 'node:http';
|
|
17
19
|
import 'node:https';
|
|
18
20
|
import 'node:zlib';
|
|
19
21
|
import 'node:stream';
|
|
20
22
|
import 'node:util';
|
|
21
23
|
import 'node:url';
|
|
24
|
+
import 'stream';
|
|
22
25
|
|
|
23
|
-
/**
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
26
|
+
/**
|
|
27
|
+
* Hash using djb2
|
|
28
|
+
* @param {import('types/hooks').StrictBody} value
|
|
29
|
+
*/
|
|
30
|
+
function hash(value) {
|
|
31
|
+
let hash = 5381;
|
|
32
|
+
let i = value.length;
|
|
27
33
|
|
|
28
|
-
|
|
29
|
-
|
|
34
|
+
if (typeof value === 'string') {
|
|
35
|
+
while (i) hash = (hash * 33) ^ value.charCodeAt(--i);
|
|
36
|
+
} else {
|
|
37
|
+
while (i) hash = (hash * 33) ^ value[--i];
|
|
30
38
|
}
|
|
31
39
|
|
|
32
|
-
return
|
|
40
|
+
return (hash >>> 0).toString(36);
|
|
33
41
|
}
|
|
34
42
|
|
|
43
|
+
/** @param {Record<string, any>} obj */
|
|
44
|
+
|
|
35
45
|
/** @param {Record<string, string>} params */
|
|
36
46
|
function decode_params(params) {
|
|
37
47
|
for (const key in params) {
|
|
@@ -56,11 +66,9 @@ function decode_params(params) {
|
|
|
56
66
|
|
|
57
67
|
/** @param {string} body */
|
|
58
68
|
function error(body) {
|
|
59
|
-
return {
|
|
60
|
-
status: 500
|
|
61
|
-
|
|
62
|
-
headers: {}
|
|
63
|
-
};
|
|
69
|
+
return new Response(body, {
|
|
70
|
+
status: 500
|
|
71
|
+
});
|
|
64
72
|
}
|
|
65
73
|
|
|
66
74
|
/** @param {unknown} s */
|
|
@@ -89,16 +97,16 @@ function is_text(content_type) {
|
|
|
89
97
|
}
|
|
90
98
|
|
|
91
99
|
/**
|
|
92
|
-
* @param {import('types/hooks').
|
|
100
|
+
* @param {import('types/hooks').RequestEvent} event
|
|
93
101
|
* @param {import('types/internal').SSREndpoint} route
|
|
94
102
|
* @param {RegExpExecArray} match
|
|
95
|
-
* @returns {Promise<
|
|
103
|
+
* @returns {Promise<Response | undefined>}
|
|
96
104
|
*/
|
|
97
|
-
async function render_endpoint(
|
|
105
|
+
async function render_endpoint(event, route, match) {
|
|
98
106
|
const mod = await route.load();
|
|
99
107
|
|
|
100
108
|
/** @type {import('types/endpoint').RequestHandler} */
|
|
101
|
-
const handler = mod[request.method.toLowerCase().replace('delete', 'del')]; // 'delete' is a reserved word
|
|
109
|
+
const handler = mod[event.request.method.toLowerCase().replace('delete', 'del')]; // 'delete' is a reserved word
|
|
102
110
|
|
|
103
111
|
if (!handler) {
|
|
104
112
|
return;
|
|
@@ -107,10 +115,10 @@ async function render_endpoint(request, route, match) {
|
|
|
107
115
|
// we're mutating `request` so that we don't have to do { ...request, params }
|
|
108
116
|
// on the next line, since that breaks the getters that replace path, query and
|
|
109
117
|
// origin. We could revert that once we remove the getters
|
|
110
|
-
|
|
118
|
+
event.params = route.params ? decode_params(route.params(match)) : {};
|
|
111
119
|
|
|
112
|
-
const response = await handler(
|
|
113
|
-
const preface = `Invalid response from route ${
|
|
120
|
+
const response = await handler(event);
|
|
121
|
+
const preface = `Invalid response from route ${event.url.pathname}`;
|
|
114
122
|
|
|
115
123
|
if (typeof response !== 'object') {
|
|
116
124
|
return error(`${preface}: expected an object, got ${typeof response}`);
|
|
@@ -120,10 +128,11 @@ async function render_endpoint(request, route, match) {
|
|
|
120
128
|
return;
|
|
121
129
|
}
|
|
122
130
|
|
|
123
|
-
|
|
131
|
+
const { status = 200, body = {} } = response;
|
|
132
|
+
const headers =
|
|
133
|
+
response.headers instanceof Headers ? response.headers : to_headers(response.headers);
|
|
124
134
|
|
|
125
|
-
|
|
126
|
-
const type = get_single_valued_header(headers, 'content-type');
|
|
135
|
+
const type = headers.get('content-type');
|
|
127
136
|
|
|
128
137
|
if (!is_text(type) && !(body instanceof Uint8Array || is_string(body))) {
|
|
129
138
|
return error(
|
|
@@ -134,19 +143,45 @@ async function render_endpoint(request, route, match) {
|
|
|
134
143
|
/** @type {import('types/hooks').StrictBody} */
|
|
135
144
|
let normalized_body;
|
|
136
145
|
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
!(body instanceof Uint8Array) &&
|
|
141
|
-
(!type || type.startsWith('application/json'))
|
|
142
|
-
) {
|
|
143
|
-
headers = { ...headers, 'content-type': 'application/json; charset=utf-8' };
|
|
144
|
-
normalized_body = JSON.stringify(typeof body === 'undefined' ? {} : body);
|
|
146
|
+
if (is_pojo(body) && (!type || type.startsWith('application/json'))) {
|
|
147
|
+
headers.set('content-type', 'application/json; charset=utf-8');
|
|
148
|
+
normalized_body = JSON.stringify(body);
|
|
145
149
|
} else {
|
|
146
150
|
normalized_body = /** @type {import('types/hooks').StrictBody} */ (body);
|
|
147
151
|
}
|
|
148
152
|
|
|
149
|
-
|
|
153
|
+
if (
|
|
154
|
+
(typeof normalized_body === 'string' || normalized_body instanceof Uint8Array) &&
|
|
155
|
+
!headers.has('etag')
|
|
156
|
+
) {
|
|
157
|
+
const cache_control = headers.get('cache-control');
|
|
158
|
+
if (!cache_control || !/(no-store|immutable)/.test(cache_control)) {
|
|
159
|
+
headers.set('etag', `"${hash(normalized_body)}"`);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
return new Response(normalized_body, {
|
|
164
|
+
status,
|
|
165
|
+
headers
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/** @param {any} body */
|
|
170
|
+
function is_pojo(body) {
|
|
171
|
+
if (typeof body !== 'object') return false;
|
|
172
|
+
|
|
173
|
+
if (body) {
|
|
174
|
+
if (body instanceof Uint8Array) return false;
|
|
175
|
+
|
|
176
|
+
// body could be a node Readable, but we don't want to import
|
|
177
|
+
// node built-ins, so we use duck typing
|
|
178
|
+
if (body._readableState && body._writableState && body._events) return false;
|
|
179
|
+
|
|
180
|
+
// similarly, it could be a web ReadableStream
|
|
181
|
+
if (body[Symbol.toStringTag] === 'ReadableStream') return false;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
return true;
|
|
150
185
|
}
|
|
151
186
|
|
|
152
187
|
var chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_$';
|
|
@@ -428,23 +463,6 @@ function writable(value, start = noop) {
|
|
|
428
463
|
return { set, update, subscribe };
|
|
429
464
|
}
|
|
430
465
|
|
|
431
|
-
/**
|
|
432
|
-
* Hash using djb2
|
|
433
|
-
* @param {import('types/hooks').StrictBody} value
|
|
434
|
-
*/
|
|
435
|
-
function hash(value) {
|
|
436
|
-
let hash = 5381;
|
|
437
|
-
let i = value.length;
|
|
438
|
-
|
|
439
|
-
if (typeof value === 'string') {
|
|
440
|
-
while (i) hash = (hash * 33) ^ value.charCodeAt(--i);
|
|
441
|
-
} else {
|
|
442
|
-
while (i) hash = (hash * 33) ^ value[--i];
|
|
443
|
-
}
|
|
444
|
-
|
|
445
|
-
return (hash >>> 0).toString(36);
|
|
446
|
-
}
|
|
447
|
-
|
|
448
466
|
/** @type {Record<string, string>} */
|
|
449
467
|
const escape_json_string_in_html_dict = {
|
|
450
468
|
'"': '\\"',
|
|
@@ -678,8 +696,8 @@ async function render_response({
|
|
|
678
696
|
}
|
|
679
697
|
// prettier-ignore
|
|
680
698
|
head += Array.from(css)
|
|
681
|
-
|
|
682
|
-
|
|
699
|
+
.map((dep) => `\n\t<link${styles.has(dep) ? ' disabled media="(max-width: 0)"' : ''} rel="stylesheet" href="${options.prefix + dep}">`)
|
|
700
|
+
.join('');
|
|
683
701
|
|
|
684
702
|
if (page_config.router || page_config.hydrate) {
|
|
685
703
|
head += Array.from(js)
|
|
@@ -730,32 +748,29 @@ async function render_response({
|
|
|
730
748
|
}
|
|
731
749
|
}
|
|
732
750
|
|
|
733
|
-
|
|
734
|
-
const
|
|
735
|
-
'
|
|
736
|
-
|
|
751
|
+
const segments = url.pathname.slice(options.paths.base.length).split('/').slice(2);
|
|
752
|
+
const assets =
|
|
753
|
+
options.paths.assets || (segments.length > 0 ? segments.map(() => '..').join('/') : '.');
|
|
754
|
+
|
|
755
|
+
const html = options.template({ head, body, assets });
|
|
756
|
+
|
|
757
|
+
const headers = new Headers({
|
|
758
|
+
'content-type': 'text/html',
|
|
759
|
+
etag: `"${hash(html)}"`
|
|
760
|
+
});
|
|
737
761
|
|
|
738
762
|
if (maxage) {
|
|
739
|
-
headers
|
|
763
|
+
headers.set('cache-control', `${is_private ? 'private' : 'public'}, max-age=${maxage}`);
|
|
740
764
|
}
|
|
741
765
|
|
|
742
766
|
if (!options.floc) {
|
|
743
|
-
headers
|
|
767
|
+
headers.set('permissions-policy', 'interest-cohort=()');
|
|
744
768
|
}
|
|
745
769
|
|
|
746
|
-
|
|
747
|
-
const assets =
|
|
748
|
-
options.paths.assets || (segments.length > 0 ? segments.map(() => '..').join('/') : '.');
|
|
749
|
-
|
|
750
|
-
return {
|
|
770
|
+
return new Response(html, {
|
|
751
771
|
status,
|
|
752
|
-
headers
|
|
753
|
-
|
|
754
|
-
head,
|
|
755
|
-
body,
|
|
756
|
-
assets
|
|
757
|
-
})
|
|
758
|
-
};
|
|
772
|
+
headers
|
|
773
|
+
});
|
|
759
774
|
}
|
|
760
775
|
|
|
761
776
|
/**
|
|
@@ -854,7 +869,7 @@ function normalize(loaded) {
|
|
|
854
869
|
|
|
855
870
|
/**
|
|
856
871
|
* @param {{
|
|
857
|
-
*
|
|
872
|
+
* event: import('types/hooks').RequestEvent;
|
|
858
873
|
* options: import('types/internal').SSRRenderOptions;
|
|
859
874
|
* state: import('types/internal').SSRRenderState;
|
|
860
875
|
* route: import('types/internal').SSRPage | null;
|
|
@@ -870,7 +885,7 @@ function normalize(loaded) {
|
|
|
870
885
|
* @returns {Promise<import('./types').Loaded | undefined>} undefined for fallthrough
|
|
871
886
|
*/
|
|
872
887
|
async function load_node({
|
|
873
|
-
|
|
888
|
+
event,
|
|
874
889
|
options,
|
|
875
890
|
state,
|
|
876
891
|
route,
|
|
@@ -941,7 +956,7 @@ async function load_node({
|
|
|
941
956
|
|
|
942
957
|
opts.headers = new Headers(opts.headers);
|
|
943
958
|
|
|
944
|
-
const resolved = resolve(
|
|
959
|
+
const resolved = resolve(event.url.pathname, requested.split('?')[0]);
|
|
945
960
|
|
|
946
961
|
let response;
|
|
947
962
|
|
|
@@ -977,12 +992,15 @@ async function load_node({
|
|
|
977
992
|
if (opts.credentials !== 'omit') {
|
|
978
993
|
uses_credentials = true;
|
|
979
994
|
|
|
980
|
-
|
|
981
|
-
|
|
995
|
+
const cookie = event.request.headers.get('cookie');
|
|
996
|
+
const authorization = event.request.headers.get('authorization');
|
|
997
|
+
|
|
998
|
+
if (cookie) {
|
|
999
|
+
opts.headers.set('cookie', cookie);
|
|
982
1000
|
}
|
|
983
1001
|
|
|
984
|
-
if (
|
|
985
|
-
opts.headers.set('authorization',
|
|
1002
|
+
if (authorization && !opts.headers.has('authorization')) {
|
|
1003
|
+
opts.headers.set('authorization', authorization);
|
|
986
1004
|
}
|
|
987
1005
|
}
|
|
988
1006
|
|
|
@@ -995,12 +1013,7 @@ async function load_node({
|
|
|
995
1013
|
}
|
|
996
1014
|
|
|
997
1015
|
const rendered = await respond(
|
|
998
|
-
|
|
999
|
-
url: new URL(requested, request.url),
|
|
1000
|
-
method: opts.method || 'GET',
|
|
1001
|
-
headers: Object.fromEntries(opts.headers),
|
|
1002
|
-
rawBody: opts.body == null ? null : new TextEncoder().encode(opts.body)
|
|
1003
|
-
},
|
|
1016
|
+
new Request(new URL(requested, event.url).href, opts),
|
|
1004
1017
|
options,
|
|
1005
1018
|
{
|
|
1006
1019
|
fetched: requested,
|
|
@@ -1013,17 +1026,11 @@ async function load_node({
|
|
|
1013
1026
|
state.prerender.dependencies.set(relative, rendered);
|
|
1014
1027
|
}
|
|
1015
1028
|
|
|
1016
|
-
|
|
1017
|
-
// can be an array so we know we have only simple values
|
|
1018
|
-
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie
|
|
1019
|
-
response = new Response(rendered.body, {
|
|
1020
|
-
status: rendered.status,
|
|
1021
|
-
headers: /** @type {Record<string, string>} */ (rendered.headers)
|
|
1022
|
-
});
|
|
1029
|
+
response = rendered;
|
|
1023
1030
|
} else {
|
|
1024
1031
|
// we can't load the endpoint from our own manifest,
|
|
1025
1032
|
// so we need to make an actual HTTP request
|
|
1026
|
-
return fetch(new URL(requested,
|
|
1033
|
+
return fetch(new URL(requested, event.url).href, {
|
|
1027
1034
|
method: opts.method || 'GET',
|
|
1028
1035
|
headers: opts.headers
|
|
1029
1036
|
});
|
|
@@ -1046,11 +1053,13 @@ async function load_node({
|
|
|
1046
1053
|
// ports do not affect the resolution
|
|
1047
1054
|
// leading dot prevents mydomain.com matching domain.com
|
|
1048
1055
|
if (
|
|
1049
|
-
`.${new URL(requested).hostname}`.endsWith(`.${
|
|
1056
|
+
`.${new URL(requested).hostname}`.endsWith(`.${event.url.hostname}`) &&
|
|
1050
1057
|
opts.credentials !== 'omit'
|
|
1051
1058
|
) {
|
|
1052
1059
|
uses_credentials = true;
|
|
1053
|
-
|
|
1060
|
+
|
|
1061
|
+
const cookie = event.request.headers.get('cookie');
|
|
1062
|
+
if (cookie) opts.headers.set('cookie', cookie);
|
|
1054
1063
|
}
|
|
1055
1064
|
|
|
1056
1065
|
const external_request = new Request(requested, /** @type {RequestInit} */ (opts));
|
|
@@ -1159,7 +1168,7 @@ async function load_node({
|
|
|
1159
1168
|
|
|
1160
1169
|
/**
|
|
1161
1170
|
* @param {{
|
|
1162
|
-
*
|
|
1171
|
+
* event: import('types/hooks').RequestEvent;
|
|
1163
1172
|
* options: SSRRenderOptions;
|
|
1164
1173
|
* state: SSRRenderState;
|
|
1165
1174
|
* $session: any;
|
|
@@ -1168,15 +1177,7 @@ async function load_node({
|
|
|
1168
1177
|
* ssr: boolean;
|
|
1169
1178
|
* }} opts
|
|
1170
1179
|
*/
|
|
1171
|
-
async function respond_with_error({
|
|
1172
|
-
request,
|
|
1173
|
-
options,
|
|
1174
|
-
state,
|
|
1175
|
-
$session,
|
|
1176
|
-
status,
|
|
1177
|
-
error,
|
|
1178
|
-
ssr
|
|
1179
|
-
}) {
|
|
1180
|
+
async function respond_with_error({ event, options, state, $session, status, error, ssr }) {
|
|
1180
1181
|
try {
|
|
1181
1182
|
const default_layout = await options.manifest._.nodes[0](); // 0 is always the root layout
|
|
1182
1183
|
const default_error = await options.manifest._.nodes[1](); // 1 is always the root error
|
|
@@ -1186,11 +1187,11 @@ async function respond_with_error({
|
|
|
1186
1187
|
|
|
1187
1188
|
const layout_loaded = /** @type {Loaded} */ (
|
|
1188
1189
|
await load_node({
|
|
1189
|
-
|
|
1190
|
+
event,
|
|
1190
1191
|
options,
|
|
1191
1192
|
state,
|
|
1192
1193
|
route: null,
|
|
1193
|
-
url:
|
|
1194
|
+
url: event.url, // TODO this is redundant, no?
|
|
1194
1195
|
params,
|
|
1195
1196
|
node: default_layout,
|
|
1196
1197
|
$session,
|
|
@@ -1201,11 +1202,11 @@ async function respond_with_error({
|
|
|
1201
1202
|
|
|
1202
1203
|
const error_loaded = /** @type {Loaded} */ (
|
|
1203
1204
|
await load_node({
|
|
1204
|
-
|
|
1205
|
+
event,
|
|
1205
1206
|
options,
|
|
1206
1207
|
state,
|
|
1207
1208
|
route: null,
|
|
1208
|
-
url:
|
|
1209
|
+
url: event.url,
|
|
1209
1210
|
params,
|
|
1210
1211
|
node: default_error,
|
|
1211
1212
|
$session,
|
|
@@ -1228,26 +1229,23 @@ async function respond_with_error({
|
|
|
1228
1229
|
status,
|
|
1229
1230
|
error,
|
|
1230
1231
|
branch: [layout_loaded, error_loaded],
|
|
1231
|
-
url:
|
|
1232
|
+
url: event.url,
|
|
1232
1233
|
params,
|
|
1233
1234
|
ssr
|
|
1234
1235
|
});
|
|
1235
1236
|
} catch (err) {
|
|
1236
1237
|
const error = coalesce_to_error(err);
|
|
1237
1238
|
|
|
1238
|
-
options.handle_error(error,
|
|
1239
|
+
options.handle_error(error, event);
|
|
1239
1240
|
|
|
1240
|
-
return {
|
|
1241
|
-
status: 500
|
|
1242
|
-
|
|
1243
|
-
body: error.stack
|
|
1244
|
-
};
|
|
1241
|
+
return new Response(error.stack, {
|
|
1242
|
+
status: 500
|
|
1243
|
+
});
|
|
1245
1244
|
}
|
|
1246
1245
|
}
|
|
1247
1246
|
|
|
1248
1247
|
/**
|
|
1249
1248
|
* @typedef {import('./types.js').Loaded} Loaded
|
|
1250
|
-
* @typedef {import('types/hooks').ServerResponse} ServerResponse
|
|
1251
1249
|
* @typedef {import('types/internal').SSRNode} SSRNode
|
|
1252
1250
|
* @typedef {import('types/internal').SSRRenderOptions} SSRRenderOptions
|
|
1253
1251
|
* @typedef {import('types/internal').SSRRenderState} SSRRenderState
|
|
@@ -1255,7 +1253,7 @@ async function respond_with_error({
|
|
|
1255
1253
|
|
|
1256
1254
|
/**
|
|
1257
1255
|
* @param {{
|
|
1258
|
-
*
|
|
1256
|
+
* event: import('types/hooks').RequestEvent;
|
|
1259
1257
|
* options: SSRRenderOptions;
|
|
1260
1258
|
* state: SSRRenderState;
|
|
1261
1259
|
* $session: any;
|
|
@@ -1263,10 +1261,10 @@ async function respond_with_error({
|
|
|
1263
1261
|
* params: Record<string, string>;
|
|
1264
1262
|
* ssr: boolean;
|
|
1265
1263
|
* }} opts
|
|
1266
|
-
* @returns {Promise<
|
|
1264
|
+
* @returns {Promise<Response | undefined>}
|
|
1267
1265
|
*/
|
|
1268
1266
|
async function respond$1(opts) {
|
|
1269
|
-
const {
|
|
1267
|
+
const { event, options, state, $session, route, ssr } = opts;
|
|
1270
1268
|
|
|
1271
1269
|
/** @type {Array<SSRNode | undefined>} */
|
|
1272
1270
|
let nodes;
|
|
@@ -1280,7 +1278,7 @@ async function respond$1(opts) {
|
|
|
1280
1278
|
router: true
|
|
1281
1279
|
},
|
|
1282
1280
|
status: 200,
|
|
1283
|
-
url:
|
|
1281
|
+
url: event.url,
|
|
1284
1282
|
stuff: {}
|
|
1285
1283
|
});
|
|
1286
1284
|
}
|
|
@@ -1292,10 +1290,10 @@ async function respond$1(opts) {
|
|
|
1292
1290
|
} catch (err) {
|
|
1293
1291
|
const error = coalesce_to_error(err);
|
|
1294
1292
|
|
|
1295
|
-
options.handle_error(error,
|
|
1293
|
+
options.handle_error(error, event);
|
|
1296
1294
|
|
|
1297
1295
|
return await respond_with_error({
|
|
1298
|
-
|
|
1296
|
+
event,
|
|
1299
1297
|
options,
|
|
1300
1298
|
state,
|
|
1301
1299
|
$session,
|
|
@@ -1313,10 +1311,9 @@ async function respond$1(opts) {
|
|
|
1313
1311
|
if (!leaf.prerender && state.prerender && !state.prerender.all) {
|
|
1314
1312
|
// if the page has `export const prerender = true`, continue,
|
|
1315
1313
|
// otherwise bail out at this point
|
|
1316
|
-
return {
|
|
1317
|
-
status: 204
|
|
1318
|
-
|
|
1319
|
-
};
|
|
1314
|
+
return new Response(undefined, {
|
|
1315
|
+
status: 204
|
|
1316
|
+
});
|
|
1320
1317
|
}
|
|
1321
1318
|
|
|
1322
1319
|
/** @type {Array<Loaded>} */
|
|
@@ -1344,7 +1341,7 @@ async function respond$1(opts) {
|
|
|
1344
1341
|
try {
|
|
1345
1342
|
loaded = await load_node({
|
|
1346
1343
|
...opts,
|
|
1347
|
-
url:
|
|
1344
|
+
url: event.url,
|
|
1348
1345
|
node,
|
|
1349
1346
|
stuff,
|
|
1350
1347
|
is_error: false
|
|
@@ -1356,12 +1353,12 @@ async function respond$1(opts) {
|
|
|
1356
1353
|
|
|
1357
1354
|
if (loaded.loaded.redirect) {
|
|
1358
1355
|
return with_cookies(
|
|
1359
|
-
{
|
|
1356
|
+
new Response(undefined, {
|
|
1360
1357
|
status: loaded.loaded.status,
|
|
1361
1358
|
headers: {
|
|
1362
1359
|
location: encodeURI(loaded.loaded.redirect)
|
|
1363
1360
|
}
|
|
1364
|
-
},
|
|
1361
|
+
}),
|
|
1365
1362
|
set_cookie_headers
|
|
1366
1363
|
);
|
|
1367
1364
|
}
|
|
@@ -1372,7 +1369,7 @@ async function respond$1(opts) {
|
|
|
1372
1369
|
} catch (err) {
|
|
1373
1370
|
const e = coalesce_to_error(err);
|
|
1374
1371
|
|
|
1375
|
-
options.handle_error(e,
|
|
1372
|
+
options.handle_error(e, event);
|
|
1376
1373
|
|
|
1377
1374
|
status = 500;
|
|
1378
1375
|
error = e;
|
|
@@ -1398,7 +1395,7 @@ async function respond$1(opts) {
|
|
|
1398
1395
|
const error_loaded = /** @type {import('./types').Loaded} */ (
|
|
1399
1396
|
await load_node({
|
|
1400
1397
|
...opts,
|
|
1401
|
-
url:
|
|
1398
|
+
url: event.url,
|
|
1402
1399
|
node: error_node,
|
|
1403
1400
|
stuff: node_loaded.stuff,
|
|
1404
1401
|
is_error: true,
|
|
@@ -1418,7 +1415,7 @@ async function respond$1(opts) {
|
|
|
1418
1415
|
} catch (err) {
|
|
1419
1416
|
const e = coalesce_to_error(err);
|
|
1420
1417
|
|
|
1421
|
-
options.handle_error(e,
|
|
1418
|
+
options.handle_error(e, event);
|
|
1422
1419
|
|
|
1423
1420
|
continue;
|
|
1424
1421
|
}
|
|
@@ -1430,7 +1427,7 @@ async function respond$1(opts) {
|
|
|
1430
1427
|
// for now just return regular error page
|
|
1431
1428
|
return with_cookies(
|
|
1432
1429
|
await respond_with_error({
|
|
1433
|
-
|
|
1430
|
+
event,
|
|
1434
1431
|
options,
|
|
1435
1432
|
state,
|
|
1436
1433
|
$session,
|
|
@@ -1457,7 +1454,7 @@ async function respond$1(opts) {
|
|
|
1457
1454
|
await render_response({
|
|
1458
1455
|
...opts,
|
|
1459
1456
|
stuff,
|
|
1460
|
-
url:
|
|
1457
|
+
url: event.url,
|
|
1461
1458
|
page_config,
|
|
1462
1459
|
status,
|
|
1463
1460
|
error,
|
|
@@ -1468,7 +1465,7 @@ async function respond$1(opts) {
|
|
|
1468
1465
|
} catch (err) {
|
|
1469
1466
|
const error = coalesce_to_error(err);
|
|
1470
1467
|
|
|
1471
|
-
options.handle_error(error,
|
|
1468
|
+
options.handle_error(error, event);
|
|
1472
1469
|
|
|
1473
1470
|
return with_cookies(
|
|
1474
1471
|
await respond_with_error({
|
|
@@ -1500,41 +1497,41 @@ function get_page_config(leaf, options) {
|
|
|
1500
1497
|
}
|
|
1501
1498
|
|
|
1502
1499
|
/**
|
|
1503
|
-
* @param {
|
|
1500
|
+
* @param {Response} response
|
|
1504
1501
|
* @param {string[]} set_cookie_headers
|
|
1505
1502
|
*/
|
|
1506
1503
|
function with_cookies(response, set_cookie_headers) {
|
|
1507
1504
|
if (set_cookie_headers.length) {
|
|
1508
|
-
|
|
1505
|
+
set_cookie_headers.forEach((value) => {
|
|
1506
|
+
response.headers.append('set-cookie', value);
|
|
1507
|
+
});
|
|
1509
1508
|
}
|
|
1510
1509
|
return response;
|
|
1511
1510
|
}
|
|
1512
1511
|
|
|
1513
1512
|
/**
|
|
1514
|
-
* @param {import('types/hooks').
|
|
1513
|
+
* @param {import('types/hooks').RequestEvent} event
|
|
1515
1514
|
* @param {import('types/internal').SSRPage} route
|
|
1516
1515
|
* @param {RegExpExecArray} match
|
|
1517
1516
|
* @param {import('types/internal').SSRRenderOptions} options
|
|
1518
1517
|
* @param {import('types/internal').SSRRenderState} state
|
|
1519
1518
|
* @param {boolean} ssr
|
|
1520
|
-
* @returns {Promise<
|
|
1519
|
+
* @returns {Promise<Response | undefined>}
|
|
1521
1520
|
*/
|
|
1522
|
-
async function render_page(
|
|
1521
|
+
async function render_page(event, route, match, options, state, ssr) {
|
|
1523
1522
|
if (state.initiator === route) {
|
|
1524
1523
|
// infinite request cycle detected
|
|
1525
|
-
return {
|
|
1526
|
-
status: 404
|
|
1527
|
-
|
|
1528
|
-
body: `Not found: ${request.url.pathname}`
|
|
1529
|
-
};
|
|
1524
|
+
return new Response(`Not found: ${event.url.pathname}`, {
|
|
1525
|
+
status: 404
|
|
1526
|
+
});
|
|
1530
1527
|
}
|
|
1531
1528
|
|
|
1532
1529
|
const params = route.params ? decode_params(route.params(match)) : {};
|
|
1533
1530
|
|
|
1534
|
-
const $session = await options.hooks.getSession(
|
|
1531
|
+
const $session = await options.hooks.getSession(event);
|
|
1535
1532
|
|
|
1536
1533
|
const response = await respond$1({
|
|
1537
|
-
|
|
1534
|
+
event,
|
|
1538
1535
|
options,
|
|
1539
1536
|
state,
|
|
1540
1537
|
$session,
|
|
@@ -1552,290 +1549,119 @@ async function render_page(request, route, match, options, state, ssr) {
|
|
|
1552
1549
|
// rather than render the error page — which could lead to an
|
|
1553
1550
|
// infinite loop, if the `load` belonged to the root layout,
|
|
1554
1551
|
// we respond with a bare-bones 500
|
|
1555
|
-
return {
|
|
1556
|
-
status: 500
|
|
1557
|
-
headers: {},
|
|
1558
|
-
body: `Bad request in load function: failed to fetch ${state.fetched}`
|
|
1559
|
-
};
|
|
1560
|
-
}
|
|
1561
|
-
}
|
|
1562
|
-
|
|
1563
|
-
function read_only_form_data() {
|
|
1564
|
-
/** @type {Map<string, string[]>} */
|
|
1565
|
-
const map = new Map();
|
|
1566
|
-
|
|
1567
|
-
return {
|
|
1568
|
-
/**
|
|
1569
|
-
* @param {string} key
|
|
1570
|
-
* @param {string} value
|
|
1571
|
-
*/
|
|
1572
|
-
append(key, value) {
|
|
1573
|
-
const existing_values = map.get(key);
|
|
1574
|
-
if (existing_values) {
|
|
1575
|
-
existing_values.push(value);
|
|
1576
|
-
} else {
|
|
1577
|
-
map.set(key, [value]);
|
|
1578
|
-
}
|
|
1579
|
-
},
|
|
1580
|
-
|
|
1581
|
-
data: new ReadOnlyFormData(map)
|
|
1582
|
-
};
|
|
1583
|
-
}
|
|
1584
|
-
|
|
1585
|
-
class ReadOnlyFormData {
|
|
1586
|
-
/** @type {Map<string, string[]>} */
|
|
1587
|
-
#map;
|
|
1588
|
-
|
|
1589
|
-
/** @param {Map<string, string[]>} map */
|
|
1590
|
-
constructor(map) {
|
|
1591
|
-
this.#map = map;
|
|
1592
|
-
}
|
|
1593
|
-
|
|
1594
|
-
/** @param {string} key */
|
|
1595
|
-
get(key) {
|
|
1596
|
-
const value = this.#map.get(key);
|
|
1597
|
-
if (!value) {
|
|
1598
|
-
return null;
|
|
1599
|
-
}
|
|
1600
|
-
return value[0];
|
|
1601
|
-
}
|
|
1602
|
-
|
|
1603
|
-
/** @param {string} key */
|
|
1604
|
-
getAll(key) {
|
|
1605
|
-
return this.#map.get(key) || [];
|
|
1606
|
-
}
|
|
1607
|
-
|
|
1608
|
-
/** @param {string} key */
|
|
1609
|
-
has(key) {
|
|
1610
|
-
return this.#map.has(key);
|
|
1611
|
-
}
|
|
1612
|
-
|
|
1613
|
-
*[Symbol.iterator]() {
|
|
1614
|
-
for (const [key, value] of this.#map) {
|
|
1615
|
-
for (let i = 0; i < value.length; i += 1) {
|
|
1616
|
-
yield [key, value[i]];
|
|
1617
|
-
}
|
|
1618
|
-
}
|
|
1619
|
-
}
|
|
1620
|
-
|
|
1621
|
-
*entries() {
|
|
1622
|
-
for (const [key, value] of this.#map) {
|
|
1623
|
-
for (let i = 0; i < value.length; i += 1) {
|
|
1624
|
-
yield [key, value[i]];
|
|
1625
|
-
}
|
|
1626
|
-
}
|
|
1627
|
-
}
|
|
1628
|
-
|
|
1629
|
-
*keys() {
|
|
1630
|
-
for (const [key] of this.#map) yield key;
|
|
1631
|
-
}
|
|
1632
|
-
|
|
1633
|
-
*values() {
|
|
1634
|
-
for (const [, value] of this.#map) {
|
|
1635
|
-
for (let i = 0; i < value.length; i += 1) {
|
|
1636
|
-
yield value[i];
|
|
1637
|
-
}
|
|
1638
|
-
}
|
|
1639
|
-
}
|
|
1640
|
-
}
|
|
1641
|
-
|
|
1642
|
-
/**
|
|
1643
|
-
* @param {import('types/app').RawBody} raw
|
|
1644
|
-
* @param {import('types/helper').RequestHeaders} headers
|
|
1645
|
-
*/
|
|
1646
|
-
function parse_body(raw, headers) {
|
|
1647
|
-
if (!raw) return raw;
|
|
1648
|
-
|
|
1649
|
-
const content_type = headers['content-type'];
|
|
1650
|
-
const [type, ...directives] = content_type ? content_type.split(/;\s*/) : [];
|
|
1651
|
-
|
|
1652
|
-
const text = () => new TextDecoder(headers['content-encoding'] || 'utf-8').decode(raw);
|
|
1653
|
-
|
|
1654
|
-
switch (type) {
|
|
1655
|
-
case 'text/plain':
|
|
1656
|
-
return text();
|
|
1657
|
-
|
|
1658
|
-
case 'application/json':
|
|
1659
|
-
return JSON.parse(text());
|
|
1660
|
-
|
|
1661
|
-
case 'application/x-www-form-urlencoded':
|
|
1662
|
-
return get_urlencoded(text());
|
|
1663
|
-
|
|
1664
|
-
case 'multipart/form-data': {
|
|
1665
|
-
const boundary = directives.find((directive) => directive.startsWith('boundary='));
|
|
1666
|
-
if (!boundary) throw new Error('Missing boundary');
|
|
1667
|
-
return get_multipart(text(), boundary.slice('boundary='.length));
|
|
1668
|
-
}
|
|
1669
|
-
default:
|
|
1670
|
-
return raw;
|
|
1671
|
-
}
|
|
1672
|
-
}
|
|
1673
|
-
|
|
1674
|
-
/** @param {string} text */
|
|
1675
|
-
function get_urlencoded(text) {
|
|
1676
|
-
const { data, append } = read_only_form_data();
|
|
1677
|
-
|
|
1678
|
-
text
|
|
1679
|
-
.replace(/\+/g, ' ')
|
|
1680
|
-
.split('&')
|
|
1681
|
-
.forEach((str) => {
|
|
1682
|
-
const [key, value] = str.split('=');
|
|
1683
|
-
append(decodeURIComponent(key), decodeURIComponent(value));
|
|
1552
|
+
return new Response(`Bad request in load function: failed to fetch ${state.fetched}`, {
|
|
1553
|
+
status: 500
|
|
1684
1554
|
});
|
|
1685
|
-
|
|
1686
|
-
return data;
|
|
1687
|
-
}
|
|
1688
|
-
|
|
1689
|
-
/**
|
|
1690
|
-
* @param {string} text
|
|
1691
|
-
* @param {string} boundary
|
|
1692
|
-
*/
|
|
1693
|
-
function get_multipart(text, boundary) {
|
|
1694
|
-
const parts = text.split(`--${boundary}`);
|
|
1695
|
-
|
|
1696
|
-
if (parts[0] !== '' || parts[parts.length - 1].trim() !== '--') {
|
|
1697
|
-
throw new Error('Malformed form data');
|
|
1698
1555
|
}
|
|
1699
|
-
|
|
1700
|
-
const { data, append } = read_only_form_data();
|
|
1701
|
-
|
|
1702
|
-
parts.slice(1, -1).forEach((part) => {
|
|
1703
|
-
const match = /\s*([\s\S]+?)\r\n\r\n([\s\S]*)\s*/.exec(part);
|
|
1704
|
-
if (!match) {
|
|
1705
|
-
throw new Error('Malformed form data');
|
|
1706
|
-
}
|
|
1707
|
-
const raw_headers = match[1];
|
|
1708
|
-
const body = match[2].trim();
|
|
1709
|
-
|
|
1710
|
-
let key;
|
|
1711
|
-
|
|
1712
|
-
/** @type {Record<string, string>} */
|
|
1713
|
-
const headers = {};
|
|
1714
|
-
raw_headers.split('\r\n').forEach((str) => {
|
|
1715
|
-
const [raw_header, ...raw_directives] = str.split('; ');
|
|
1716
|
-
let [name, value] = raw_header.split(': ');
|
|
1717
|
-
|
|
1718
|
-
name = name.toLowerCase();
|
|
1719
|
-
headers[name] = value;
|
|
1720
|
-
|
|
1721
|
-
/** @type {Record<string, string>} */
|
|
1722
|
-
const directives = {};
|
|
1723
|
-
raw_directives.forEach((raw_directive) => {
|
|
1724
|
-
const [name, value] = raw_directive.split('=');
|
|
1725
|
-
directives[name] = JSON.parse(value); // TODO is this right?
|
|
1726
|
-
});
|
|
1727
|
-
|
|
1728
|
-
if (name === 'content-disposition') {
|
|
1729
|
-
if (value !== 'form-data') throw new Error('Malformed form data');
|
|
1730
|
-
|
|
1731
|
-
if (directives.filename) {
|
|
1732
|
-
// TODO we probably don't want to do this automatically
|
|
1733
|
-
throw new Error('File upload is not yet implemented');
|
|
1734
|
-
}
|
|
1735
|
-
|
|
1736
|
-
if (directives.name) {
|
|
1737
|
-
key = directives.name;
|
|
1738
|
-
}
|
|
1739
|
-
}
|
|
1740
|
-
});
|
|
1741
|
-
|
|
1742
|
-
if (!key) throw new Error('Malformed form data');
|
|
1743
|
-
|
|
1744
|
-
append(key, body);
|
|
1745
|
-
});
|
|
1746
|
-
|
|
1747
|
-
return data;
|
|
1748
1556
|
}
|
|
1749
1557
|
|
|
1750
|
-
/** @type {import('
|
|
1751
|
-
async function respond(
|
|
1752
|
-
|
|
1753
|
-
|
|
1558
|
+
/** @type {import('types/internal').Respond} */
|
|
1559
|
+
async function respond(request, options, state = {}) {
|
|
1560
|
+
const url = new URL(request.url);
|
|
1561
|
+
|
|
1562
|
+
if (url.pathname !== '/' && options.trailing_slash !== 'ignore') {
|
|
1563
|
+
const has_trailing_slash = url.pathname.endsWith('/');
|
|
1754
1564
|
|
|
1755
1565
|
if (
|
|
1756
1566
|
(has_trailing_slash && options.trailing_slash === 'never') ||
|
|
1757
1567
|
(!has_trailing_slash &&
|
|
1758
1568
|
options.trailing_slash === 'always' &&
|
|
1759
|
-
!(
|
|
1569
|
+
!(url.pathname.split('/').pop() || '').includes('.'))
|
|
1760
1570
|
) {
|
|
1761
|
-
|
|
1762
|
-
? incoming.url.pathname.slice(0, -1)
|
|
1763
|
-
: incoming.url.pathname + '/';
|
|
1571
|
+
url.pathname = has_trailing_slash ? url.pathname.slice(0, -1) : url.pathname + '/';
|
|
1764
1572
|
|
|
1765
|
-
if (
|
|
1573
|
+
if (url.search === '?') url.search = '';
|
|
1766
1574
|
|
|
1767
|
-
return {
|
|
1575
|
+
return new Response(undefined, {
|
|
1768
1576
|
status: 301,
|
|
1769
1577
|
headers: {
|
|
1770
|
-
location:
|
|
1578
|
+
location: url.pathname + url.search
|
|
1771
1579
|
}
|
|
1772
|
-
};
|
|
1580
|
+
});
|
|
1773
1581
|
}
|
|
1774
1582
|
}
|
|
1775
1583
|
|
|
1776
|
-
const headers = lowercase_keys(incoming.headers);
|
|
1777
|
-
const request = {
|
|
1778
|
-
...incoming,
|
|
1779
|
-
headers,
|
|
1780
|
-
body: parse_body(incoming.rawBody, headers),
|
|
1781
|
-
params: {},
|
|
1782
|
-
locals: {}
|
|
1783
|
-
};
|
|
1784
|
-
|
|
1785
1584
|
const { parameter, allowed } = options.method_override;
|
|
1786
|
-
const method_override =
|
|
1585
|
+
const method_override = url.searchParams.get(parameter)?.toUpperCase();
|
|
1787
1586
|
|
|
1788
1587
|
if (method_override) {
|
|
1789
|
-
if (request.method
|
|
1588
|
+
if (request.method === 'POST') {
|
|
1790
1589
|
if (allowed.includes(method_override)) {
|
|
1791
|
-
request
|
|
1590
|
+
request = new Proxy(request, {
|
|
1591
|
+
get: (target, property, _receiver) => {
|
|
1592
|
+
if (property === 'method') return method_override;
|
|
1593
|
+
return Reflect.get(target, property, target);
|
|
1594
|
+
}
|
|
1595
|
+
});
|
|
1792
1596
|
} else {
|
|
1793
1597
|
const verb = allowed.length === 0 ? 'enabled' : 'allowed';
|
|
1794
1598
|
const body = `${parameter}=${method_override} is not ${verb}. See https://kit.svelte.dev/docs#configuration-methodoverride`;
|
|
1795
1599
|
|
|
1796
|
-
return {
|
|
1797
|
-
status: 400
|
|
1798
|
-
|
|
1799
|
-
body
|
|
1800
|
-
};
|
|
1600
|
+
return new Response(body, {
|
|
1601
|
+
status: 400
|
|
1602
|
+
});
|
|
1801
1603
|
}
|
|
1802
1604
|
} else {
|
|
1803
1605
|
throw new Error(`${parameter}=${method_override} is only allowed with POST requests`);
|
|
1804
1606
|
}
|
|
1805
1607
|
}
|
|
1806
1608
|
|
|
1609
|
+
/** @type {import('types/hooks').RequestEvent} */
|
|
1610
|
+
const event = {
|
|
1611
|
+
request,
|
|
1612
|
+
url,
|
|
1613
|
+
params: {},
|
|
1614
|
+
locals: {}
|
|
1615
|
+
};
|
|
1616
|
+
|
|
1807
1617
|
// TODO remove this for 1.0
|
|
1808
1618
|
/**
|
|
1809
1619
|
* @param {string} property
|
|
1810
1620
|
* @param {string} replacement
|
|
1621
|
+
* @param {string} suffix
|
|
1811
1622
|
*/
|
|
1812
|
-
const
|
|
1813
|
-
|
|
1814
|
-
|
|
1815
|
-
|
|
1816
|
-
|
|
1817
|
-
|
|
1623
|
+
const removed = (property, replacement, suffix = '') => ({
|
|
1624
|
+
get: () => {
|
|
1625
|
+
throw new Error(`event.${property} has been replaced by event.${replacement}` + suffix);
|
|
1626
|
+
}
|
|
1627
|
+
});
|
|
1628
|
+
|
|
1629
|
+
const details = '. See https://github.com/sveltejs/kit/pull/3384 for details';
|
|
1630
|
+
|
|
1631
|
+
const body_getter = {
|
|
1632
|
+
get: () => {
|
|
1633
|
+
throw new Error(
|
|
1634
|
+
'To access the request body use the text/json/arrayBuffer/formData methods, e.g. `body = await request.json()`' +
|
|
1635
|
+
details
|
|
1636
|
+
);
|
|
1637
|
+
}
|
|
1818
1638
|
};
|
|
1819
1639
|
|
|
1820
|
-
|
|
1821
|
-
|
|
1822
|
-
|
|
1640
|
+
Object.defineProperties(event, {
|
|
1641
|
+
method: removed('method', 'request.method', details),
|
|
1642
|
+
headers: removed('headers', 'request.headers', details),
|
|
1643
|
+
origin: removed('origin', 'url.origin'),
|
|
1644
|
+
path: removed('path', 'url.pathname'),
|
|
1645
|
+
query: removed('query', 'url.searchParams'),
|
|
1646
|
+
body: body_getter,
|
|
1647
|
+
rawBody: body_getter
|
|
1648
|
+
});
|
|
1823
1649
|
|
|
1824
1650
|
let ssr = true;
|
|
1825
1651
|
|
|
1826
1652
|
try {
|
|
1827
1653
|
return await options.hooks.handle({
|
|
1828
|
-
|
|
1829
|
-
resolve: async (
|
|
1654
|
+
event,
|
|
1655
|
+
resolve: async (event, opts) => {
|
|
1830
1656
|
if (opts && 'ssr' in opts) ssr = /** @type {boolean} */ (opts.ssr);
|
|
1831
1657
|
|
|
1832
1658
|
if (state.prerender && state.prerender.fallback) {
|
|
1833
1659
|
return await render_response({
|
|
1834
|
-
url:
|
|
1835
|
-
params:
|
|
1660
|
+
url: event.url,
|
|
1661
|
+
params: event.params,
|
|
1836
1662
|
options,
|
|
1837
1663
|
state,
|
|
1838
|
-
$session: await options.hooks.getSession(
|
|
1664
|
+
$session: await options.hooks.getSession(event),
|
|
1839
1665
|
page_config: { router: true, hydrate: true },
|
|
1840
1666
|
stuff: {},
|
|
1841
1667
|
status: 200,
|
|
@@ -1844,7 +1670,12 @@ async function respond(incoming, options, state = {}) {
|
|
|
1844
1670
|
});
|
|
1845
1671
|
}
|
|
1846
1672
|
|
|
1847
|
-
|
|
1673
|
+
let decoded = decodeURI(event.url.pathname);
|
|
1674
|
+
|
|
1675
|
+
if (options.paths.base) {
|
|
1676
|
+
if (!decoded.startsWith(options.paths.base)) return;
|
|
1677
|
+
decoded = decoded.slice(options.paths.base.length) || '/';
|
|
1678
|
+
}
|
|
1848
1679
|
|
|
1849
1680
|
for (const route of options.manifest._.routes) {
|
|
1850
1681
|
const match = route.pattern.exec(decoded);
|
|
@@ -1852,46 +1683,40 @@ async function respond(incoming, options, state = {}) {
|
|
|
1852
1683
|
|
|
1853
1684
|
const response =
|
|
1854
1685
|
route.type === 'endpoint'
|
|
1855
|
-
? await render_endpoint(
|
|
1856
|
-
: await render_page(
|
|
1686
|
+
? await render_endpoint(event, route, match)
|
|
1687
|
+
: await render_page(event, route, match, options, state, ssr);
|
|
1857
1688
|
|
|
1858
1689
|
if (response) {
|
|
1859
|
-
//
|
|
1860
|
-
if (response.status === 200) {
|
|
1861
|
-
|
|
1862
|
-
if (!cache_control || !/(no-store|immutable)/.test(cache_control)) {
|
|
1863
|
-
let if_none_match_value = request.headers['if-none-match'];
|
|
1864
|
-
// ignore W/ prefix https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/If-None-Match#directives
|
|
1865
|
-
if (if_none_match_value?.startsWith('W/"')) {
|
|
1866
|
-
if_none_match_value = if_none_match_value.substring(2);
|
|
1867
|
-
}
|
|
1690
|
+
// respond with 304 if etag matches
|
|
1691
|
+
if (response.status === 200 && response.headers.has('etag')) {
|
|
1692
|
+
let if_none_match_value = request.headers.get('if-none-match');
|
|
1868
1693
|
|
|
1869
|
-
|
|
1870
|
-
|
|
1871
|
-
|
|
1872
|
-
|
|
1873
|
-
const headers = { etag };
|
|
1874
|
-
|
|
1875
|
-
// https://datatracker.ietf.org/doc/html/rfc7232#section-4.1
|
|
1876
|
-
for (const key of [
|
|
1877
|
-
'cache-control',
|
|
1878
|
-
'content-location',
|
|
1879
|
-
'date',
|
|
1880
|
-
'expires',
|
|
1881
|
-
'vary'
|
|
1882
|
-
]) {
|
|
1883
|
-
if (key in response.headers) {
|
|
1884
|
-
headers[key] = /** @type {string} */ (response.headers[key]);
|
|
1885
|
-
}
|
|
1886
|
-
}
|
|
1694
|
+
// ignore W/ prefix https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/If-None-Match#directives
|
|
1695
|
+
if (if_none_match_value?.startsWith('W/"')) {
|
|
1696
|
+
if_none_match_value = if_none_match_value.substring(2);
|
|
1697
|
+
}
|
|
1887
1698
|
|
|
1888
|
-
|
|
1889
|
-
|
|
1890
|
-
|
|
1891
|
-
|
|
1699
|
+
const etag = /** @type {string} */ (response.headers.get('etag'));
|
|
1700
|
+
|
|
1701
|
+
if (if_none_match_value === etag) {
|
|
1702
|
+
const headers = new Headers({ etag });
|
|
1703
|
+
|
|
1704
|
+
// https://datatracker.ietf.org/doc/html/rfc7232#section-4.1
|
|
1705
|
+
for (const key of [
|
|
1706
|
+
'cache-control',
|
|
1707
|
+
'content-location',
|
|
1708
|
+
'date',
|
|
1709
|
+
'expires',
|
|
1710
|
+
'vary'
|
|
1711
|
+
]) {
|
|
1712
|
+
const value = response.headers.get(key);
|
|
1713
|
+
if (value) headers.set(key, value);
|
|
1892
1714
|
}
|
|
1893
1715
|
|
|
1894
|
-
|
|
1716
|
+
return new Response(undefined, {
|
|
1717
|
+
status: 304,
|
|
1718
|
+
headers
|
|
1719
|
+
});
|
|
1895
1720
|
}
|
|
1896
1721
|
}
|
|
1897
1722
|
|
|
@@ -1902,28 +1727,34 @@ async function respond(incoming, options, state = {}) {
|
|
|
1902
1727
|
// if this request came direct from the user, rather than
|
|
1903
1728
|
// via a `fetch` in a `load`, render a 404 page
|
|
1904
1729
|
if (!state.initiator) {
|
|
1905
|
-
const $session = await options.hooks.getSession(
|
|
1730
|
+
const $session = await options.hooks.getSession(event);
|
|
1906
1731
|
return await respond_with_error({
|
|
1907
|
-
|
|
1732
|
+
event,
|
|
1908
1733
|
options,
|
|
1909
1734
|
state,
|
|
1910
1735
|
$session,
|
|
1911
1736
|
status: 404,
|
|
1912
|
-
error: new Error(`Not found: ${
|
|
1737
|
+
error: new Error(`Not found: ${event.url.pathname}`),
|
|
1913
1738
|
ssr
|
|
1914
1739
|
});
|
|
1915
1740
|
}
|
|
1741
|
+
},
|
|
1742
|
+
|
|
1743
|
+
// TODO remove for 1.0
|
|
1744
|
+
// @ts-expect-error
|
|
1745
|
+
get request() {
|
|
1746
|
+
throw new Error('request in handle has been replaced with event' + details);
|
|
1916
1747
|
}
|
|
1917
1748
|
});
|
|
1918
1749
|
} catch (/** @type {unknown} */ e) {
|
|
1919
1750
|
const error = coalesce_to_error(e);
|
|
1920
1751
|
|
|
1921
|
-
options.handle_error(error,
|
|
1752
|
+
options.handle_error(error, event);
|
|
1922
1753
|
|
|
1923
1754
|
try {
|
|
1924
|
-
const $session = await options.hooks.getSession(
|
|
1755
|
+
const $session = await options.hooks.getSession(event);
|
|
1925
1756
|
return await respond_with_error({
|
|
1926
|
-
|
|
1757
|
+
event,
|
|
1927
1758
|
options,
|
|
1928
1759
|
state,
|
|
1929
1760
|
$session,
|
|
@@ -1934,11 +1765,9 @@ async function respond(incoming, options, state = {}) {
|
|
|
1934
1765
|
} catch (/** @type {unknown} */ e) {
|
|
1935
1766
|
const error = coalesce_to_error(e);
|
|
1936
1767
|
|
|
1937
|
-
return {
|
|
1938
|
-
status: 500
|
|
1939
|
-
|
|
1940
|
-
body: options.dev ? error.stack : error.message
|
|
1941
|
-
};
|
|
1768
|
+
return new Response(options.dev ? error.stack : error.message, {
|
|
1769
|
+
status: 500
|
|
1770
|
+
});
|
|
1942
1771
|
}
|
|
1943
1772
|
}
|
|
1944
1773
|
}
|
|
@@ -2057,6 +1886,14 @@ async function create_plugin(config, cwd) {
|
|
|
2057
1886
|
vite.watcher.on('add', update_manifest);
|
|
2058
1887
|
vite.watcher.on('remove', update_manifest);
|
|
2059
1888
|
|
|
1889
|
+
const assets = config.kit.paths.assets ? SVELTE_KIT_ASSETS : config.kit.paths.base;
|
|
1890
|
+
const asset_server = sirv(config.kit.files.assets, {
|
|
1891
|
+
dev: true,
|
|
1892
|
+
etag: true,
|
|
1893
|
+
maxAge: 0,
|
|
1894
|
+
extensions: []
|
|
1895
|
+
});
|
|
1896
|
+
|
|
2060
1897
|
return () => {
|
|
2061
1898
|
remove_html_middlewares(vite.middlewares);
|
|
2062
1899
|
|
|
@@ -2065,8 +1902,24 @@ async function create_plugin(config, cwd) {
|
|
|
2065
1902
|
if (!req.url || !req.method) throw new Error('Incomplete request');
|
|
2066
1903
|
if (req.url === '/favicon.ico') return not_found(res);
|
|
2067
1904
|
|
|
2068
|
-
const
|
|
2069
|
-
|
|
1905
|
+
const url = new URL$1(
|
|
1906
|
+
`${vite.config.server.https ? 'https' : 'http'}://${req.headers.host}${req.url}`
|
|
1907
|
+
);
|
|
1908
|
+
|
|
1909
|
+
const decoded = decodeURI(url.pathname);
|
|
1910
|
+
|
|
1911
|
+
if (decoded.startsWith(assets)) {
|
|
1912
|
+
const pathname = decoded.slice(assets.length);
|
|
1913
|
+
const file = config.kit.files.assets + pathname;
|
|
1914
|
+
|
|
1915
|
+
if (fs__default.existsSync(file) && !fs__default.statSync(file).isDirectory()) {
|
|
1916
|
+
req.url = encodeURI(pathname); // don't need query/hash
|
|
1917
|
+
asset_server(req, res);
|
|
1918
|
+
return;
|
|
1919
|
+
}
|
|
1920
|
+
}
|
|
1921
|
+
|
|
1922
|
+
if (!decoded.startsWith(config.kit.paths.base)) return not_found(res);
|
|
2070
1923
|
|
|
2071
1924
|
/** @type {Partial<import('types/internal').Hooks>} */
|
|
2072
1925
|
const user_hooks = resolve_entry(config.kit.files.hooks)
|
|
@@ -2076,7 +1929,7 @@ async function create_plugin(config, cwd) {
|
|
|
2076
1929
|
/** @type {import('types/internal').Hooks} */
|
|
2077
1930
|
const hooks = {
|
|
2078
1931
|
getSession: user_hooks.getSession || (() => ({})),
|
|
2079
|
-
handle: user_hooks.handle || (({
|
|
1932
|
+
handle: user_hooks.handle || (({ event, resolve }) => resolve(event)),
|
|
2080
1933
|
handleError:
|
|
2081
1934
|
user_hooks.handleError ||
|
|
2082
1935
|
(({ /** @type {Error & { frame?: string }} */ error }) => {
|
|
@@ -2110,7 +1963,7 @@ async function create_plugin(config, cwd) {
|
|
|
2110
1963
|
|
|
2111
1964
|
paths.set_paths({
|
|
2112
1965
|
base: config.kit.paths.base,
|
|
2113
|
-
assets
|
|
1966
|
+
assets
|
|
2114
1967
|
});
|
|
2115
1968
|
|
|
2116
1969
|
let body;
|
|
@@ -2123,14 +1976,11 @@ async function create_plugin(config, cwd) {
|
|
|
2123
1976
|
}
|
|
2124
1977
|
|
|
2125
1978
|
const rendered = await respond(
|
|
2126
|
-
{
|
|
2127
|
-
|
|
2128
|
-
`${vite.config.server.https ? 'https' : 'http'}://${req.headers.host}${req.url}`
|
|
2129
|
-
),
|
|
2130
|
-
headers: /** @type {import('types/helper').RequestHeaders} */ (req.headers),
|
|
1979
|
+
new Request(url.href, {
|
|
1980
|
+
headers: /** @type {Record<string, string>} */ (req.headers),
|
|
2131
1981
|
method: req.method,
|
|
2132
|
-
|
|
2133
|
-
},
|
|
1982
|
+
body
|
|
1983
|
+
}),
|
|
2134
1984
|
{
|
|
2135
1985
|
amp: config.kit.amp,
|
|
2136
1986
|
dev: true,
|
|
@@ -2139,9 +1989,20 @@ async function create_plugin(config, cwd) {
|
|
|
2139
1989
|
vite.ssrFixStacktrace(error);
|
|
2140
1990
|
return error.stack;
|
|
2141
1991
|
},
|
|
2142
|
-
handle_error: (error,
|
|
1992
|
+
handle_error: (error, event) => {
|
|
2143
1993
|
vite.ssrFixStacktrace(error);
|
|
2144
|
-
hooks.handleError({
|
|
1994
|
+
hooks.handleError({
|
|
1995
|
+
error,
|
|
1996
|
+
event,
|
|
1997
|
+
|
|
1998
|
+
// TODO remove for 1.0
|
|
1999
|
+
// @ts-expect-error
|
|
2000
|
+
get request() {
|
|
2001
|
+
throw new Error(
|
|
2002
|
+
'request in handleError has been replaced with event. See https://github.com/sveltejs/kit/pull/3384 for details'
|
|
2003
|
+
);
|
|
2004
|
+
}
|
|
2005
|
+
});
|
|
2145
2006
|
},
|
|
2146
2007
|
hooks,
|
|
2147
2008
|
hydrate: config.kit.hydrate,
|
|
@@ -2149,7 +2010,7 @@ async function create_plugin(config, cwd) {
|
|
|
2149
2010
|
method_override: config.kit.methodOverride,
|
|
2150
2011
|
paths: {
|
|
2151
2012
|
base: config.kit.paths.base,
|
|
2152
|
-
assets
|
|
2013
|
+
assets
|
|
2153
2014
|
},
|
|
2154
2015
|
prefix: '',
|
|
2155
2016
|
prerender: config.kit.prerender.enabled,
|
|
@@ -2214,9 +2075,7 @@ async function create_plugin(config, cwd) {
|
|
|
2214
2075
|
);
|
|
2215
2076
|
|
|
2216
2077
|
if (rendered) {
|
|
2217
|
-
res
|
|
2218
|
-
if (rendered.body) res.write(rendered.body);
|
|
2219
|
-
res.end();
|
|
2078
|
+
setResponse(res, rendered);
|
|
2220
2079
|
} else {
|
|
2221
2080
|
not_found(res);
|
|
2222
2081
|
}
|
|
@@ -2352,7 +2211,6 @@ async function dev({ cwd, port, host, https, config }) {
|
|
|
2352
2211
|
}),
|
|
2353
2212
|
await create_plugin(config, cwd)
|
|
2354
2213
|
],
|
|
2355
|
-
publicDir: config.kit.files.assets,
|
|
2356
2214
|
base: '/'
|
|
2357
2215
|
});
|
|
2358
2216
|
|