@sveltejs/kit 1.0.0-next.233 → 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/server/index.js +261 -441
- package/dist/chunks/{build.js → http.js} +23 -1
- package/dist/chunks/index.js +266 -437
- package/dist/chunks/index3.js +15 -20
- package/dist/chunks/index5.js +24 -39
- package/dist/chunks/index6.js +16 -13
- package/dist/chunks/url.js +1 -23
- package/dist/cli.js +28 -7
- package/dist/hooks.js +8 -8
- 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
|
@@ -5,11 +5,11 @@ import { c as create_manifest_data, a as create_app, d as deep_merge } from './i
|
|
|
5
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 { s as sirv } from './
|
|
9
|
-
import { g as get_single_valued_header, r as resolve, i as is_root_relative } from './url.js';
|
|
8
|
+
import { t as to_headers, s as sirv } from './http.js';
|
|
10
9
|
import { s } from './misc.js';
|
|
10
|
+
import { r as resolve, i as is_root_relative } from './url.js';
|
|
11
11
|
import { __fetch_polyfill } from '../install-fetch.js';
|
|
12
|
-
import { getRawBody } from '../node.js';
|
|
12
|
+
import { getRawBody, setResponse } from '../node.js';
|
|
13
13
|
import 'sade';
|
|
14
14
|
import 'child_process';
|
|
15
15
|
import 'net';
|
|
@@ -21,19 +21,27 @@ import 'node:zlib';
|
|
|
21
21
|
import 'node:stream';
|
|
22
22
|
import 'node:util';
|
|
23
23
|
import 'node:url';
|
|
24
|
+
import 'stream';
|
|
24
25
|
|
|
25
|
-
/**
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
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;
|
|
29
33
|
|
|
30
|
-
|
|
31
|
-
|
|
34
|
+
if (typeof value === 'string') {
|
|
35
|
+
while (i) hash = (hash * 33) ^ value.charCodeAt(--i);
|
|
36
|
+
} else {
|
|
37
|
+
while (i) hash = (hash * 33) ^ value[--i];
|
|
32
38
|
}
|
|
33
39
|
|
|
34
|
-
return
|
|
40
|
+
return (hash >>> 0).toString(36);
|
|
35
41
|
}
|
|
36
42
|
|
|
43
|
+
/** @param {Record<string, any>} obj */
|
|
44
|
+
|
|
37
45
|
/** @param {Record<string, string>} params */
|
|
38
46
|
function decode_params(params) {
|
|
39
47
|
for (const key in params) {
|
|
@@ -58,11 +66,9 @@ function decode_params(params) {
|
|
|
58
66
|
|
|
59
67
|
/** @param {string} body */
|
|
60
68
|
function error(body) {
|
|
61
|
-
return {
|
|
62
|
-
status: 500
|
|
63
|
-
|
|
64
|
-
headers: {}
|
|
65
|
-
};
|
|
69
|
+
return new Response(body, {
|
|
70
|
+
status: 500
|
|
71
|
+
});
|
|
66
72
|
}
|
|
67
73
|
|
|
68
74
|
/** @param {unknown} s */
|
|
@@ -91,16 +97,16 @@ function is_text(content_type) {
|
|
|
91
97
|
}
|
|
92
98
|
|
|
93
99
|
/**
|
|
94
|
-
* @param {import('types/hooks').
|
|
100
|
+
* @param {import('types/hooks').RequestEvent} event
|
|
95
101
|
* @param {import('types/internal').SSREndpoint} route
|
|
96
102
|
* @param {RegExpExecArray} match
|
|
97
|
-
* @returns {Promise<
|
|
103
|
+
* @returns {Promise<Response | undefined>}
|
|
98
104
|
*/
|
|
99
|
-
async function render_endpoint(
|
|
105
|
+
async function render_endpoint(event, route, match) {
|
|
100
106
|
const mod = await route.load();
|
|
101
107
|
|
|
102
108
|
/** @type {import('types/endpoint').RequestHandler} */
|
|
103
|
-
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
|
|
104
110
|
|
|
105
111
|
if (!handler) {
|
|
106
112
|
return;
|
|
@@ -109,10 +115,10 @@ async function render_endpoint(request, route, match) {
|
|
|
109
115
|
// we're mutating `request` so that we don't have to do { ...request, params }
|
|
110
116
|
// on the next line, since that breaks the getters that replace path, query and
|
|
111
117
|
// origin. We could revert that once we remove the getters
|
|
112
|
-
|
|
118
|
+
event.params = route.params ? decode_params(route.params(match)) : {};
|
|
113
119
|
|
|
114
|
-
const response = await handler(
|
|
115
|
-
const preface = `Invalid response from route ${
|
|
120
|
+
const response = await handler(event);
|
|
121
|
+
const preface = `Invalid response from route ${event.url.pathname}`;
|
|
116
122
|
|
|
117
123
|
if (typeof response !== 'object') {
|
|
118
124
|
return error(`${preface}: expected an object, got ${typeof response}`);
|
|
@@ -122,10 +128,11 @@ async function render_endpoint(request, route, match) {
|
|
|
122
128
|
return;
|
|
123
129
|
}
|
|
124
130
|
|
|
125
|
-
|
|
131
|
+
const { status = 200, body = {} } = response;
|
|
132
|
+
const headers =
|
|
133
|
+
response.headers instanceof Headers ? response.headers : to_headers(response.headers);
|
|
126
134
|
|
|
127
|
-
|
|
128
|
-
const type = get_single_valued_header(headers, 'content-type');
|
|
135
|
+
const type = headers.get('content-type');
|
|
129
136
|
|
|
130
137
|
if (!is_text(type) && !(body instanceof Uint8Array || is_string(body))) {
|
|
131
138
|
return error(
|
|
@@ -136,19 +143,45 @@ async function render_endpoint(request, route, match) {
|
|
|
136
143
|
/** @type {import('types/hooks').StrictBody} */
|
|
137
144
|
let normalized_body;
|
|
138
145
|
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
!(body instanceof Uint8Array) &&
|
|
143
|
-
(!type || type.startsWith('application/json'))
|
|
144
|
-
) {
|
|
145
|
-
headers = { ...headers, 'content-type': 'application/json; charset=utf-8' };
|
|
146
|
-
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);
|
|
147
149
|
} else {
|
|
148
150
|
normalized_body = /** @type {import('types/hooks').StrictBody} */ (body);
|
|
149
151
|
}
|
|
150
152
|
|
|
151
|
-
|
|
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;
|
|
152
185
|
}
|
|
153
186
|
|
|
154
187
|
var chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_$';
|
|
@@ -430,23 +463,6 @@ function writable(value, start = noop) {
|
|
|
430
463
|
return { set, update, subscribe };
|
|
431
464
|
}
|
|
432
465
|
|
|
433
|
-
/**
|
|
434
|
-
* Hash using djb2
|
|
435
|
-
* @param {import('types/hooks').StrictBody} value
|
|
436
|
-
*/
|
|
437
|
-
function hash(value) {
|
|
438
|
-
let hash = 5381;
|
|
439
|
-
let i = value.length;
|
|
440
|
-
|
|
441
|
-
if (typeof value === 'string') {
|
|
442
|
-
while (i) hash = (hash * 33) ^ value.charCodeAt(--i);
|
|
443
|
-
} else {
|
|
444
|
-
while (i) hash = (hash * 33) ^ value[--i];
|
|
445
|
-
}
|
|
446
|
-
|
|
447
|
-
return (hash >>> 0).toString(36);
|
|
448
|
-
}
|
|
449
|
-
|
|
450
466
|
/** @type {Record<string, string>} */
|
|
451
467
|
const escape_json_string_in_html_dict = {
|
|
452
468
|
'"': '\\"',
|
|
@@ -732,32 +748,29 @@ async function render_response({
|
|
|
732
748
|
}
|
|
733
749
|
}
|
|
734
750
|
|
|
735
|
-
|
|
736
|
-
const
|
|
737
|
-
'
|
|
738
|
-
|
|
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
|
+
});
|
|
739
761
|
|
|
740
762
|
if (maxage) {
|
|
741
|
-
headers
|
|
763
|
+
headers.set('cache-control', `${is_private ? 'private' : 'public'}, max-age=${maxage}`);
|
|
742
764
|
}
|
|
743
765
|
|
|
744
766
|
if (!options.floc) {
|
|
745
|
-
headers
|
|
767
|
+
headers.set('permissions-policy', 'interest-cohort=()');
|
|
746
768
|
}
|
|
747
769
|
|
|
748
|
-
|
|
749
|
-
const assets =
|
|
750
|
-
options.paths.assets || (segments.length > 0 ? segments.map(() => '..').join('/') : '.');
|
|
751
|
-
|
|
752
|
-
return {
|
|
770
|
+
return new Response(html, {
|
|
753
771
|
status,
|
|
754
|
-
headers
|
|
755
|
-
|
|
756
|
-
head,
|
|
757
|
-
body,
|
|
758
|
-
assets
|
|
759
|
-
})
|
|
760
|
-
};
|
|
772
|
+
headers
|
|
773
|
+
});
|
|
761
774
|
}
|
|
762
775
|
|
|
763
776
|
/**
|
|
@@ -856,7 +869,7 @@ function normalize(loaded) {
|
|
|
856
869
|
|
|
857
870
|
/**
|
|
858
871
|
* @param {{
|
|
859
|
-
*
|
|
872
|
+
* event: import('types/hooks').RequestEvent;
|
|
860
873
|
* options: import('types/internal').SSRRenderOptions;
|
|
861
874
|
* state: import('types/internal').SSRRenderState;
|
|
862
875
|
* route: import('types/internal').SSRPage | null;
|
|
@@ -872,7 +885,7 @@ function normalize(loaded) {
|
|
|
872
885
|
* @returns {Promise<import('./types').Loaded | undefined>} undefined for fallthrough
|
|
873
886
|
*/
|
|
874
887
|
async function load_node({
|
|
875
|
-
|
|
888
|
+
event,
|
|
876
889
|
options,
|
|
877
890
|
state,
|
|
878
891
|
route,
|
|
@@ -943,7 +956,7 @@ async function load_node({
|
|
|
943
956
|
|
|
944
957
|
opts.headers = new Headers(opts.headers);
|
|
945
958
|
|
|
946
|
-
const resolved = resolve(
|
|
959
|
+
const resolved = resolve(event.url.pathname, requested.split('?')[0]);
|
|
947
960
|
|
|
948
961
|
let response;
|
|
949
962
|
|
|
@@ -979,12 +992,15 @@ async function load_node({
|
|
|
979
992
|
if (opts.credentials !== 'omit') {
|
|
980
993
|
uses_credentials = true;
|
|
981
994
|
|
|
982
|
-
|
|
983
|
-
|
|
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);
|
|
984
1000
|
}
|
|
985
1001
|
|
|
986
|
-
if (
|
|
987
|
-
opts.headers.set('authorization',
|
|
1002
|
+
if (authorization && !opts.headers.has('authorization')) {
|
|
1003
|
+
opts.headers.set('authorization', authorization);
|
|
988
1004
|
}
|
|
989
1005
|
}
|
|
990
1006
|
|
|
@@ -997,12 +1013,7 @@ async function load_node({
|
|
|
997
1013
|
}
|
|
998
1014
|
|
|
999
1015
|
const rendered = await respond(
|
|
1000
|
-
|
|
1001
|
-
url: new URL(requested, request.url),
|
|
1002
|
-
method: opts.method || 'GET',
|
|
1003
|
-
headers: Object.fromEntries(opts.headers),
|
|
1004
|
-
rawBody: opts.body == null ? null : new TextEncoder().encode(opts.body)
|
|
1005
|
-
},
|
|
1016
|
+
new Request(new URL(requested, event.url).href, opts),
|
|
1006
1017
|
options,
|
|
1007
1018
|
{
|
|
1008
1019
|
fetched: requested,
|
|
@@ -1015,17 +1026,11 @@ async function load_node({
|
|
|
1015
1026
|
state.prerender.dependencies.set(relative, rendered);
|
|
1016
1027
|
}
|
|
1017
1028
|
|
|
1018
|
-
|
|
1019
|
-
// can be an array so we know we have only simple values
|
|
1020
|
-
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie
|
|
1021
|
-
response = new Response(rendered.body, {
|
|
1022
|
-
status: rendered.status,
|
|
1023
|
-
headers: /** @type {Record<string, string>} */ (rendered.headers)
|
|
1024
|
-
});
|
|
1029
|
+
response = rendered;
|
|
1025
1030
|
} else {
|
|
1026
1031
|
// we can't load the endpoint from our own manifest,
|
|
1027
1032
|
// so we need to make an actual HTTP request
|
|
1028
|
-
return fetch(new URL(requested,
|
|
1033
|
+
return fetch(new URL(requested, event.url).href, {
|
|
1029
1034
|
method: opts.method || 'GET',
|
|
1030
1035
|
headers: opts.headers
|
|
1031
1036
|
});
|
|
@@ -1048,11 +1053,13 @@ async function load_node({
|
|
|
1048
1053
|
// ports do not affect the resolution
|
|
1049
1054
|
// leading dot prevents mydomain.com matching domain.com
|
|
1050
1055
|
if (
|
|
1051
|
-
`.${new URL(requested).hostname}`.endsWith(`.${
|
|
1056
|
+
`.${new URL(requested).hostname}`.endsWith(`.${event.url.hostname}`) &&
|
|
1052
1057
|
opts.credentials !== 'omit'
|
|
1053
1058
|
) {
|
|
1054
1059
|
uses_credentials = true;
|
|
1055
|
-
|
|
1060
|
+
|
|
1061
|
+
const cookie = event.request.headers.get('cookie');
|
|
1062
|
+
if (cookie) opts.headers.set('cookie', cookie);
|
|
1056
1063
|
}
|
|
1057
1064
|
|
|
1058
1065
|
const external_request = new Request(requested, /** @type {RequestInit} */ (opts));
|
|
@@ -1161,7 +1168,7 @@ async function load_node({
|
|
|
1161
1168
|
|
|
1162
1169
|
/**
|
|
1163
1170
|
* @param {{
|
|
1164
|
-
*
|
|
1171
|
+
* event: import('types/hooks').RequestEvent;
|
|
1165
1172
|
* options: SSRRenderOptions;
|
|
1166
1173
|
* state: SSRRenderState;
|
|
1167
1174
|
* $session: any;
|
|
@@ -1170,15 +1177,7 @@ async function load_node({
|
|
|
1170
1177
|
* ssr: boolean;
|
|
1171
1178
|
* }} opts
|
|
1172
1179
|
*/
|
|
1173
|
-
async function respond_with_error({
|
|
1174
|
-
request,
|
|
1175
|
-
options,
|
|
1176
|
-
state,
|
|
1177
|
-
$session,
|
|
1178
|
-
status,
|
|
1179
|
-
error,
|
|
1180
|
-
ssr
|
|
1181
|
-
}) {
|
|
1180
|
+
async function respond_with_error({ event, options, state, $session, status, error, ssr }) {
|
|
1182
1181
|
try {
|
|
1183
1182
|
const default_layout = await options.manifest._.nodes[0](); // 0 is always the root layout
|
|
1184
1183
|
const default_error = await options.manifest._.nodes[1](); // 1 is always the root error
|
|
@@ -1188,11 +1187,11 @@ async function respond_with_error({
|
|
|
1188
1187
|
|
|
1189
1188
|
const layout_loaded = /** @type {Loaded} */ (
|
|
1190
1189
|
await load_node({
|
|
1191
|
-
|
|
1190
|
+
event,
|
|
1192
1191
|
options,
|
|
1193
1192
|
state,
|
|
1194
1193
|
route: null,
|
|
1195
|
-
url:
|
|
1194
|
+
url: event.url, // TODO this is redundant, no?
|
|
1196
1195
|
params,
|
|
1197
1196
|
node: default_layout,
|
|
1198
1197
|
$session,
|
|
@@ -1203,11 +1202,11 @@ async function respond_with_error({
|
|
|
1203
1202
|
|
|
1204
1203
|
const error_loaded = /** @type {Loaded} */ (
|
|
1205
1204
|
await load_node({
|
|
1206
|
-
|
|
1205
|
+
event,
|
|
1207
1206
|
options,
|
|
1208
1207
|
state,
|
|
1209
1208
|
route: null,
|
|
1210
|
-
url:
|
|
1209
|
+
url: event.url,
|
|
1211
1210
|
params,
|
|
1212
1211
|
node: default_error,
|
|
1213
1212
|
$session,
|
|
@@ -1230,26 +1229,23 @@ async function respond_with_error({
|
|
|
1230
1229
|
status,
|
|
1231
1230
|
error,
|
|
1232
1231
|
branch: [layout_loaded, error_loaded],
|
|
1233
|
-
url:
|
|
1232
|
+
url: event.url,
|
|
1234
1233
|
params,
|
|
1235
1234
|
ssr
|
|
1236
1235
|
});
|
|
1237
1236
|
} catch (err) {
|
|
1238
1237
|
const error = coalesce_to_error(err);
|
|
1239
1238
|
|
|
1240
|
-
options.handle_error(error,
|
|
1239
|
+
options.handle_error(error, event);
|
|
1241
1240
|
|
|
1242
|
-
return {
|
|
1243
|
-
status: 500
|
|
1244
|
-
|
|
1245
|
-
body: error.stack
|
|
1246
|
-
};
|
|
1241
|
+
return new Response(error.stack, {
|
|
1242
|
+
status: 500
|
|
1243
|
+
});
|
|
1247
1244
|
}
|
|
1248
1245
|
}
|
|
1249
1246
|
|
|
1250
1247
|
/**
|
|
1251
1248
|
* @typedef {import('./types.js').Loaded} Loaded
|
|
1252
|
-
* @typedef {import('types/hooks').ServerResponse} ServerResponse
|
|
1253
1249
|
* @typedef {import('types/internal').SSRNode} SSRNode
|
|
1254
1250
|
* @typedef {import('types/internal').SSRRenderOptions} SSRRenderOptions
|
|
1255
1251
|
* @typedef {import('types/internal').SSRRenderState} SSRRenderState
|
|
@@ -1257,7 +1253,7 @@ async function respond_with_error({
|
|
|
1257
1253
|
|
|
1258
1254
|
/**
|
|
1259
1255
|
* @param {{
|
|
1260
|
-
*
|
|
1256
|
+
* event: import('types/hooks').RequestEvent;
|
|
1261
1257
|
* options: SSRRenderOptions;
|
|
1262
1258
|
* state: SSRRenderState;
|
|
1263
1259
|
* $session: any;
|
|
@@ -1265,10 +1261,10 @@ async function respond_with_error({
|
|
|
1265
1261
|
* params: Record<string, string>;
|
|
1266
1262
|
* ssr: boolean;
|
|
1267
1263
|
* }} opts
|
|
1268
|
-
* @returns {Promise<
|
|
1264
|
+
* @returns {Promise<Response | undefined>}
|
|
1269
1265
|
*/
|
|
1270
1266
|
async function respond$1(opts) {
|
|
1271
|
-
const {
|
|
1267
|
+
const { event, options, state, $session, route, ssr } = opts;
|
|
1272
1268
|
|
|
1273
1269
|
/** @type {Array<SSRNode | undefined>} */
|
|
1274
1270
|
let nodes;
|
|
@@ -1282,7 +1278,7 @@ async function respond$1(opts) {
|
|
|
1282
1278
|
router: true
|
|
1283
1279
|
},
|
|
1284
1280
|
status: 200,
|
|
1285
|
-
url:
|
|
1281
|
+
url: event.url,
|
|
1286
1282
|
stuff: {}
|
|
1287
1283
|
});
|
|
1288
1284
|
}
|
|
@@ -1294,10 +1290,10 @@ async function respond$1(opts) {
|
|
|
1294
1290
|
} catch (err) {
|
|
1295
1291
|
const error = coalesce_to_error(err);
|
|
1296
1292
|
|
|
1297
|
-
options.handle_error(error,
|
|
1293
|
+
options.handle_error(error, event);
|
|
1298
1294
|
|
|
1299
1295
|
return await respond_with_error({
|
|
1300
|
-
|
|
1296
|
+
event,
|
|
1301
1297
|
options,
|
|
1302
1298
|
state,
|
|
1303
1299
|
$session,
|
|
@@ -1315,10 +1311,9 @@ async function respond$1(opts) {
|
|
|
1315
1311
|
if (!leaf.prerender && state.prerender && !state.prerender.all) {
|
|
1316
1312
|
// if the page has `export const prerender = true`, continue,
|
|
1317
1313
|
// otherwise bail out at this point
|
|
1318
|
-
return {
|
|
1319
|
-
status: 204
|
|
1320
|
-
|
|
1321
|
-
};
|
|
1314
|
+
return new Response(undefined, {
|
|
1315
|
+
status: 204
|
|
1316
|
+
});
|
|
1322
1317
|
}
|
|
1323
1318
|
|
|
1324
1319
|
/** @type {Array<Loaded>} */
|
|
@@ -1346,7 +1341,7 @@ async function respond$1(opts) {
|
|
|
1346
1341
|
try {
|
|
1347
1342
|
loaded = await load_node({
|
|
1348
1343
|
...opts,
|
|
1349
|
-
url:
|
|
1344
|
+
url: event.url,
|
|
1350
1345
|
node,
|
|
1351
1346
|
stuff,
|
|
1352
1347
|
is_error: false
|
|
@@ -1358,12 +1353,12 @@ async function respond$1(opts) {
|
|
|
1358
1353
|
|
|
1359
1354
|
if (loaded.loaded.redirect) {
|
|
1360
1355
|
return with_cookies(
|
|
1361
|
-
{
|
|
1356
|
+
new Response(undefined, {
|
|
1362
1357
|
status: loaded.loaded.status,
|
|
1363
1358
|
headers: {
|
|
1364
1359
|
location: encodeURI(loaded.loaded.redirect)
|
|
1365
1360
|
}
|
|
1366
|
-
},
|
|
1361
|
+
}),
|
|
1367
1362
|
set_cookie_headers
|
|
1368
1363
|
);
|
|
1369
1364
|
}
|
|
@@ -1374,7 +1369,7 @@ async function respond$1(opts) {
|
|
|
1374
1369
|
} catch (err) {
|
|
1375
1370
|
const e = coalesce_to_error(err);
|
|
1376
1371
|
|
|
1377
|
-
options.handle_error(e,
|
|
1372
|
+
options.handle_error(e, event);
|
|
1378
1373
|
|
|
1379
1374
|
status = 500;
|
|
1380
1375
|
error = e;
|
|
@@ -1400,7 +1395,7 @@ async function respond$1(opts) {
|
|
|
1400
1395
|
const error_loaded = /** @type {import('./types').Loaded} */ (
|
|
1401
1396
|
await load_node({
|
|
1402
1397
|
...opts,
|
|
1403
|
-
url:
|
|
1398
|
+
url: event.url,
|
|
1404
1399
|
node: error_node,
|
|
1405
1400
|
stuff: node_loaded.stuff,
|
|
1406
1401
|
is_error: true,
|
|
@@ -1420,7 +1415,7 @@ async function respond$1(opts) {
|
|
|
1420
1415
|
} catch (err) {
|
|
1421
1416
|
const e = coalesce_to_error(err);
|
|
1422
1417
|
|
|
1423
|
-
options.handle_error(e,
|
|
1418
|
+
options.handle_error(e, event);
|
|
1424
1419
|
|
|
1425
1420
|
continue;
|
|
1426
1421
|
}
|
|
@@ -1432,7 +1427,7 @@ async function respond$1(opts) {
|
|
|
1432
1427
|
// for now just return regular error page
|
|
1433
1428
|
return with_cookies(
|
|
1434
1429
|
await respond_with_error({
|
|
1435
|
-
|
|
1430
|
+
event,
|
|
1436
1431
|
options,
|
|
1437
1432
|
state,
|
|
1438
1433
|
$session,
|
|
@@ -1459,7 +1454,7 @@ async function respond$1(opts) {
|
|
|
1459
1454
|
await render_response({
|
|
1460
1455
|
...opts,
|
|
1461
1456
|
stuff,
|
|
1462
|
-
url:
|
|
1457
|
+
url: event.url,
|
|
1463
1458
|
page_config,
|
|
1464
1459
|
status,
|
|
1465
1460
|
error,
|
|
@@ -1470,7 +1465,7 @@ async function respond$1(opts) {
|
|
|
1470
1465
|
} catch (err) {
|
|
1471
1466
|
const error = coalesce_to_error(err);
|
|
1472
1467
|
|
|
1473
|
-
options.handle_error(error,
|
|
1468
|
+
options.handle_error(error, event);
|
|
1474
1469
|
|
|
1475
1470
|
return with_cookies(
|
|
1476
1471
|
await respond_with_error({
|
|
@@ -1502,41 +1497,41 @@ function get_page_config(leaf, options) {
|
|
|
1502
1497
|
}
|
|
1503
1498
|
|
|
1504
1499
|
/**
|
|
1505
|
-
* @param {
|
|
1500
|
+
* @param {Response} response
|
|
1506
1501
|
* @param {string[]} set_cookie_headers
|
|
1507
1502
|
*/
|
|
1508
1503
|
function with_cookies(response, set_cookie_headers) {
|
|
1509
1504
|
if (set_cookie_headers.length) {
|
|
1510
|
-
|
|
1505
|
+
set_cookie_headers.forEach((value) => {
|
|
1506
|
+
response.headers.append('set-cookie', value);
|
|
1507
|
+
});
|
|
1511
1508
|
}
|
|
1512
1509
|
return response;
|
|
1513
1510
|
}
|
|
1514
1511
|
|
|
1515
1512
|
/**
|
|
1516
|
-
* @param {import('types/hooks').
|
|
1513
|
+
* @param {import('types/hooks').RequestEvent} event
|
|
1517
1514
|
* @param {import('types/internal').SSRPage} route
|
|
1518
1515
|
* @param {RegExpExecArray} match
|
|
1519
1516
|
* @param {import('types/internal').SSRRenderOptions} options
|
|
1520
1517
|
* @param {import('types/internal').SSRRenderState} state
|
|
1521
1518
|
* @param {boolean} ssr
|
|
1522
|
-
* @returns {Promise<
|
|
1519
|
+
* @returns {Promise<Response | undefined>}
|
|
1523
1520
|
*/
|
|
1524
|
-
async function render_page(
|
|
1521
|
+
async function render_page(event, route, match, options, state, ssr) {
|
|
1525
1522
|
if (state.initiator === route) {
|
|
1526
1523
|
// infinite request cycle detected
|
|
1527
|
-
return {
|
|
1528
|
-
status: 404
|
|
1529
|
-
|
|
1530
|
-
body: `Not found: ${request.url.pathname}`
|
|
1531
|
-
};
|
|
1524
|
+
return new Response(`Not found: ${event.url.pathname}`, {
|
|
1525
|
+
status: 404
|
|
1526
|
+
});
|
|
1532
1527
|
}
|
|
1533
1528
|
|
|
1534
1529
|
const params = route.params ? decode_params(route.params(match)) : {};
|
|
1535
1530
|
|
|
1536
|
-
const $session = await options.hooks.getSession(
|
|
1531
|
+
const $session = await options.hooks.getSession(event);
|
|
1537
1532
|
|
|
1538
1533
|
const response = await respond$1({
|
|
1539
|
-
|
|
1534
|
+
event,
|
|
1540
1535
|
options,
|
|
1541
1536
|
state,
|
|
1542
1537
|
$session,
|
|
@@ -1554,290 +1549,119 @@ async function render_page(request, route, match, options, state, ssr) {
|
|
|
1554
1549
|
// rather than render the error page — which could lead to an
|
|
1555
1550
|
// infinite loop, if the `load` belonged to the root layout,
|
|
1556
1551
|
// we respond with a bare-bones 500
|
|
1557
|
-
return {
|
|
1558
|
-
status: 500
|
|
1559
|
-
headers: {},
|
|
1560
|
-
body: `Bad request in load function: failed to fetch ${state.fetched}`
|
|
1561
|
-
};
|
|
1562
|
-
}
|
|
1563
|
-
}
|
|
1564
|
-
|
|
1565
|
-
function read_only_form_data() {
|
|
1566
|
-
/** @type {Map<string, string[]>} */
|
|
1567
|
-
const map = new Map();
|
|
1568
|
-
|
|
1569
|
-
return {
|
|
1570
|
-
/**
|
|
1571
|
-
* @param {string} key
|
|
1572
|
-
* @param {string} value
|
|
1573
|
-
*/
|
|
1574
|
-
append(key, value) {
|
|
1575
|
-
const existing_values = map.get(key);
|
|
1576
|
-
if (existing_values) {
|
|
1577
|
-
existing_values.push(value);
|
|
1578
|
-
} else {
|
|
1579
|
-
map.set(key, [value]);
|
|
1580
|
-
}
|
|
1581
|
-
},
|
|
1582
|
-
|
|
1583
|
-
data: new ReadOnlyFormData(map)
|
|
1584
|
-
};
|
|
1585
|
-
}
|
|
1586
|
-
|
|
1587
|
-
class ReadOnlyFormData {
|
|
1588
|
-
/** @type {Map<string, string[]>} */
|
|
1589
|
-
#map;
|
|
1590
|
-
|
|
1591
|
-
/** @param {Map<string, string[]>} map */
|
|
1592
|
-
constructor(map) {
|
|
1593
|
-
this.#map = map;
|
|
1594
|
-
}
|
|
1595
|
-
|
|
1596
|
-
/** @param {string} key */
|
|
1597
|
-
get(key) {
|
|
1598
|
-
const value = this.#map.get(key);
|
|
1599
|
-
if (!value) {
|
|
1600
|
-
return null;
|
|
1601
|
-
}
|
|
1602
|
-
return value[0];
|
|
1603
|
-
}
|
|
1604
|
-
|
|
1605
|
-
/** @param {string} key */
|
|
1606
|
-
getAll(key) {
|
|
1607
|
-
return this.#map.get(key) || [];
|
|
1608
|
-
}
|
|
1609
|
-
|
|
1610
|
-
/** @param {string} key */
|
|
1611
|
-
has(key) {
|
|
1612
|
-
return this.#map.has(key);
|
|
1613
|
-
}
|
|
1614
|
-
|
|
1615
|
-
*[Symbol.iterator]() {
|
|
1616
|
-
for (const [key, value] of this.#map) {
|
|
1617
|
-
for (let i = 0; i < value.length; i += 1) {
|
|
1618
|
-
yield [key, value[i]];
|
|
1619
|
-
}
|
|
1620
|
-
}
|
|
1621
|
-
}
|
|
1622
|
-
|
|
1623
|
-
*entries() {
|
|
1624
|
-
for (const [key, value] of this.#map) {
|
|
1625
|
-
for (let i = 0; i < value.length; i += 1) {
|
|
1626
|
-
yield [key, value[i]];
|
|
1627
|
-
}
|
|
1628
|
-
}
|
|
1629
|
-
}
|
|
1630
|
-
|
|
1631
|
-
*keys() {
|
|
1632
|
-
for (const [key] of this.#map) yield key;
|
|
1633
|
-
}
|
|
1634
|
-
|
|
1635
|
-
*values() {
|
|
1636
|
-
for (const [, value] of this.#map) {
|
|
1637
|
-
for (let i = 0; i < value.length; i += 1) {
|
|
1638
|
-
yield value[i];
|
|
1639
|
-
}
|
|
1640
|
-
}
|
|
1641
|
-
}
|
|
1642
|
-
}
|
|
1643
|
-
|
|
1644
|
-
/**
|
|
1645
|
-
* @param {import('types/app').RawBody} raw
|
|
1646
|
-
* @param {import('types/helper').RequestHeaders} headers
|
|
1647
|
-
*/
|
|
1648
|
-
function parse_body(raw, headers) {
|
|
1649
|
-
if (!raw) return raw;
|
|
1650
|
-
|
|
1651
|
-
const content_type = headers['content-type'];
|
|
1652
|
-
const [type, ...directives] = content_type ? content_type.split(/;\s*/) : [];
|
|
1653
|
-
|
|
1654
|
-
const text = () => new TextDecoder(headers['content-encoding'] || 'utf-8').decode(raw);
|
|
1655
|
-
|
|
1656
|
-
switch (type) {
|
|
1657
|
-
case 'text/plain':
|
|
1658
|
-
return text();
|
|
1659
|
-
|
|
1660
|
-
case 'application/json':
|
|
1661
|
-
return JSON.parse(text());
|
|
1662
|
-
|
|
1663
|
-
case 'application/x-www-form-urlencoded':
|
|
1664
|
-
return get_urlencoded(text());
|
|
1665
|
-
|
|
1666
|
-
case 'multipart/form-data': {
|
|
1667
|
-
const boundary = directives.find((directive) => directive.startsWith('boundary='));
|
|
1668
|
-
if (!boundary) throw new Error('Missing boundary');
|
|
1669
|
-
return get_multipart(text(), boundary.slice('boundary='.length));
|
|
1670
|
-
}
|
|
1671
|
-
default:
|
|
1672
|
-
return raw;
|
|
1673
|
-
}
|
|
1674
|
-
}
|
|
1675
|
-
|
|
1676
|
-
/** @param {string} text */
|
|
1677
|
-
function get_urlencoded(text) {
|
|
1678
|
-
const { data, append } = read_only_form_data();
|
|
1679
|
-
|
|
1680
|
-
text
|
|
1681
|
-
.replace(/\+/g, ' ')
|
|
1682
|
-
.split('&')
|
|
1683
|
-
.forEach((str) => {
|
|
1684
|
-
const [key, value] = str.split('=');
|
|
1685
|
-
append(decodeURIComponent(key), decodeURIComponent(value));
|
|
1552
|
+
return new Response(`Bad request in load function: failed to fetch ${state.fetched}`, {
|
|
1553
|
+
status: 500
|
|
1686
1554
|
});
|
|
1687
|
-
|
|
1688
|
-
return data;
|
|
1689
|
-
}
|
|
1690
|
-
|
|
1691
|
-
/**
|
|
1692
|
-
* @param {string} text
|
|
1693
|
-
* @param {string} boundary
|
|
1694
|
-
*/
|
|
1695
|
-
function get_multipart(text, boundary) {
|
|
1696
|
-
const parts = text.split(`--${boundary}`);
|
|
1697
|
-
|
|
1698
|
-
if (parts[0] !== '' || parts[parts.length - 1].trim() !== '--') {
|
|
1699
|
-
throw new Error('Malformed form data');
|
|
1700
1555
|
}
|
|
1701
|
-
|
|
1702
|
-
const { data, append } = read_only_form_data();
|
|
1703
|
-
|
|
1704
|
-
parts.slice(1, -1).forEach((part) => {
|
|
1705
|
-
const match = /\s*([\s\S]+?)\r\n\r\n([\s\S]*)\s*/.exec(part);
|
|
1706
|
-
if (!match) {
|
|
1707
|
-
throw new Error('Malformed form data');
|
|
1708
|
-
}
|
|
1709
|
-
const raw_headers = match[1];
|
|
1710
|
-
const body = match[2].trim();
|
|
1711
|
-
|
|
1712
|
-
let key;
|
|
1713
|
-
|
|
1714
|
-
/** @type {Record<string, string>} */
|
|
1715
|
-
const headers = {};
|
|
1716
|
-
raw_headers.split('\r\n').forEach((str) => {
|
|
1717
|
-
const [raw_header, ...raw_directives] = str.split('; ');
|
|
1718
|
-
let [name, value] = raw_header.split(': ');
|
|
1719
|
-
|
|
1720
|
-
name = name.toLowerCase();
|
|
1721
|
-
headers[name] = value;
|
|
1722
|
-
|
|
1723
|
-
/** @type {Record<string, string>} */
|
|
1724
|
-
const directives = {};
|
|
1725
|
-
raw_directives.forEach((raw_directive) => {
|
|
1726
|
-
const [name, value] = raw_directive.split('=');
|
|
1727
|
-
directives[name] = JSON.parse(value); // TODO is this right?
|
|
1728
|
-
});
|
|
1729
|
-
|
|
1730
|
-
if (name === 'content-disposition') {
|
|
1731
|
-
if (value !== 'form-data') throw new Error('Malformed form data');
|
|
1732
|
-
|
|
1733
|
-
if (directives.filename) {
|
|
1734
|
-
// TODO we probably don't want to do this automatically
|
|
1735
|
-
throw new Error('File upload is not yet implemented');
|
|
1736
|
-
}
|
|
1737
|
-
|
|
1738
|
-
if (directives.name) {
|
|
1739
|
-
key = directives.name;
|
|
1740
|
-
}
|
|
1741
|
-
}
|
|
1742
|
-
});
|
|
1743
|
-
|
|
1744
|
-
if (!key) throw new Error('Malformed form data');
|
|
1745
|
-
|
|
1746
|
-
append(key, body);
|
|
1747
|
-
});
|
|
1748
|
-
|
|
1749
|
-
return data;
|
|
1750
1556
|
}
|
|
1751
1557
|
|
|
1752
|
-
/** @type {import('
|
|
1753
|
-
async function respond(
|
|
1754
|
-
|
|
1755
|
-
|
|
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('/');
|
|
1756
1564
|
|
|
1757
1565
|
if (
|
|
1758
1566
|
(has_trailing_slash && options.trailing_slash === 'never') ||
|
|
1759
1567
|
(!has_trailing_slash &&
|
|
1760
1568
|
options.trailing_slash === 'always' &&
|
|
1761
|
-
!(
|
|
1569
|
+
!(url.pathname.split('/').pop() || '').includes('.'))
|
|
1762
1570
|
) {
|
|
1763
|
-
|
|
1764
|
-
? incoming.url.pathname.slice(0, -1)
|
|
1765
|
-
: incoming.url.pathname + '/';
|
|
1571
|
+
url.pathname = has_trailing_slash ? url.pathname.slice(0, -1) : url.pathname + '/';
|
|
1766
1572
|
|
|
1767
|
-
if (
|
|
1573
|
+
if (url.search === '?') url.search = '';
|
|
1768
1574
|
|
|
1769
|
-
return {
|
|
1575
|
+
return new Response(undefined, {
|
|
1770
1576
|
status: 301,
|
|
1771
1577
|
headers: {
|
|
1772
|
-
location:
|
|
1578
|
+
location: url.pathname + url.search
|
|
1773
1579
|
}
|
|
1774
|
-
};
|
|
1580
|
+
});
|
|
1775
1581
|
}
|
|
1776
1582
|
}
|
|
1777
1583
|
|
|
1778
|
-
const headers = lowercase_keys(incoming.headers);
|
|
1779
|
-
const request = {
|
|
1780
|
-
...incoming,
|
|
1781
|
-
headers,
|
|
1782
|
-
body: parse_body(incoming.rawBody, headers),
|
|
1783
|
-
params: {},
|
|
1784
|
-
locals: {}
|
|
1785
|
-
};
|
|
1786
|
-
|
|
1787
1584
|
const { parameter, allowed } = options.method_override;
|
|
1788
|
-
const method_override =
|
|
1585
|
+
const method_override = url.searchParams.get(parameter)?.toUpperCase();
|
|
1789
1586
|
|
|
1790
1587
|
if (method_override) {
|
|
1791
|
-
if (request.method
|
|
1588
|
+
if (request.method === 'POST') {
|
|
1792
1589
|
if (allowed.includes(method_override)) {
|
|
1793
|
-
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
|
+
});
|
|
1794
1596
|
} else {
|
|
1795
1597
|
const verb = allowed.length === 0 ? 'enabled' : 'allowed';
|
|
1796
1598
|
const body = `${parameter}=${method_override} is not ${verb}. See https://kit.svelte.dev/docs#configuration-methodoverride`;
|
|
1797
1599
|
|
|
1798
|
-
return {
|
|
1799
|
-
status: 400
|
|
1800
|
-
|
|
1801
|
-
body
|
|
1802
|
-
};
|
|
1600
|
+
return new Response(body, {
|
|
1601
|
+
status: 400
|
|
1602
|
+
});
|
|
1803
1603
|
}
|
|
1804
1604
|
} else {
|
|
1805
1605
|
throw new Error(`${parameter}=${method_override} is only allowed with POST requests`);
|
|
1806
1606
|
}
|
|
1807
1607
|
}
|
|
1808
1608
|
|
|
1609
|
+
/** @type {import('types/hooks').RequestEvent} */
|
|
1610
|
+
const event = {
|
|
1611
|
+
request,
|
|
1612
|
+
url,
|
|
1613
|
+
params: {},
|
|
1614
|
+
locals: {}
|
|
1615
|
+
};
|
|
1616
|
+
|
|
1809
1617
|
// TODO remove this for 1.0
|
|
1810
1618
|
/**
|
|
1811
1619
|
* @param {string} property
|
|
1812
1620
|
* @param {string} replacement
|
|
1621
|
+
* @param {string} suffix
|
|
1813
1622
|
*/
|
|
1814
|
-
const
|
|
1815
|
-
|
|
1816
|
-
|
|
1817
|
-
|
|
1818
|
-
|
|
1819
|
-
|
|
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
|
+
}
|
|
1820
1638
|
};
|
|
1821
1639
|
|
|
1822
|
-
|
|
1823
|
-
|
|
1824
|
-
|
|
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
|
+
});
|
|
1825
1649
|
|
|
1826
1650
|
let ssr = true;
|
|
1827
1651
|
|
|
1828
1652
|
try {
|
|
1829
1653
|
return await options.hooks.handle({
|
|
1830
|
-
|
|
1831
|
-
resolve: async (
|
|
1654
|
+
event,
|
|
1655
|
+
resolve: async (event, opts) => {
|
|
1832
1656
|
if (opts && 'ssr' in opts) ssr = /** @type {boolean} */ (opts.ssr);
|
|
1833
1657
|
|
|
1834
1658
|
if (state.prerender && state.prerender.fallback) {
|
|
1835
1659
|
return await render_response({
|
|
1836
|
-
url:
|
|
1837
|
-
params:
|
|
1660
|
+
url: event.url,
|
|
1661
|
+
params: event.params,
|
|
1838
1662
|
options,
|
|
1839
1663
|
state,
|
|
1840
|
-
$session: await options.hooks.getSession(
|
|
1664
|
+
$session: await options.hooks.getSession(event),
|
|
1841
1665
|
page_config: { router: true, hydrate: true },
|
|
1842
1666
|
stuff: {},
|
|
1843
1667
|
status: 200,
|
|
@@ -1846,7 +1670,7 @@ async function respond(incoming, options, state = {}) {
|
|
|
1846
1670
|
});
|
|
1847
1671
|
}
|
|
1848
1672
|
|
|
1849
|
-
let decoded = decodeURI(
|
|
1673
|
+
let decoded = decodeURI(event.url.pathname);
|
|
1850
1674
|
|
|
1851
1675
|
if (options.paths.base) {
|
|
1852
1676
|
if (!decoded.startsWith(options.paths.base)) return;
|
|
@@ -1859,47 +1683,40 @@ async function respond(incoming, options, state = {}) {
|
|
|
1859
1683
|
|
|
1860
1684
|
const response =
|
|
1861
1685
|
route.type === 'endpoint'
|
|
1862
|
-
? await render_endpoint(
|
|
1863
|
-
: await render_page(
|
|
1686
|
+
? await render_endpoint(event, route, match)
|
|
1687
|
+
: await render_page(event, route, match, options, state, ssr);
|
|
1864
1688
|
|
|
1865
1689
|
if (response) {
|
|
1866
|
-
//
|
|
1867
|
-
|
|
1868
|
-
|
|
1869
|
-
const cache_control = get_single_valued_header(response.headers, 'cache-control');
|
|
1870
|
-
if (!cache_control || !/(no-store|immutable)/.test(cache_control)) {
|
|
1871
|
-
let if_none_match_value = request.headers['if-none-match'];
|
|
1872
|
-
// ignore W/ prefix https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/If-None-Match#directives
|
|
1873
|
-
if (if_none_match_value?.startsWith('W/"')) {
|
|
1874
|
-
if_none_match_value = if_none_match_value.substring(2);
|
|
1875
|
-
}
|
|
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');
|
|
1876
1693
|
|
|
1877
|
-
|
|
1878
|
-
|
|
1879
|
-
|
|
1880
|
-
|
|
1881
|
-
const headers = { etag };
|
|
1882
|
-
|
|
1883
|
-
// https://datatracker.ietf.org/doc/html/rfc7232#section-4.1
|
|
1884
|
-
for (const key of [
|
|
1885
|
-
'cache-control',
|
|
1886
|
-
'content-location',
|
|
1887
|
-
'date',
|
|
1888
|
-
'expires',
|
|
1889
|
-
'vary'
|
|
1890
|
-
]) {
|
|
1891
|
-
if (key in response.headers) {
|
|
1892
|
-
headers[key] = /** @type {string} */ (response.headers[key]);
|
|
1893
|
-
}
|
|
1894
|
-
}
|
|
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
|
+
}
|
|
1895
1698
|
|
|
1896
|
-
|
|
1897
|
-
|
|
1898
|
-
|
|
1899
|
-
|
|
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);
|
|
1900
1714
|
}
|
|
1901
1715
|
|
|
1902
|
-
|
|
1716
|
+
return new Response(undefined, {
|
|
1717
|
+
status: 304,
|
|
1718
|
+
headers
|
|
1719
|
+
});
|
|
1903
1720
|
}
|
|
1904
1721
|
}
|
|
1905
1722
|
|
|
@@ -1910,28 +1727,34 @@ async function respond(incoming, options, state = {}) {
|
|
|
1910
1727
|
// if this request came direct from the user, rather than
|
|
1911
1728
|
// via a `fetch` in a `load`, render a 404 page
|
|
1912
1729
|
if (!state.initiator) {
|
|
1913
|
-
const $session = await options.hooks.getSession(
|
|
1730
|
+
const $session = await options.hooks.getSession(event);
|
|
1914
1731
|
return await respond_with_error({
|
|
1915
|
-
|
|
1732
|
+
event,
|
|
1916
1733
|
options,
|
|
1917
1734
|
state,
|
|
1918
1735
|
$session,
|
|
1919
1736
|
status: 404,
|
|
1920
|
-
error: new Error(`Not found: ${
|
|
1737
|
+
error: new Error(`Not found: ${event.url.pathname}`),
|
|
1921
1738
|
ssr
|
|
1922
1739
|
});
|
|
1923
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);
|
|
1924
1747
|
}
|
|
1925
1748
|
});
|
|
1926
1749
|
} catch (/** @type {unknown} */ e) {
|
|
1927
1750
|
const error = coalesce_to_error(e);
|
|
1928
1751
|
|
|
1929
|
-
options.handle_error(error,
|
|
1752
|
+
options.handle_error(error, event);
|
|
1930
1753
|
|
|
1931
1754
|
try {
|
|
1932
|
-
const $session = await options.hooks.getSession(
|
|
1755
|
+
const $session = await options.hooks.getSession(event);
|
|
1933
1756
|
return await respond_with_error({
|
|
1934
|
-
|
|
1757
|
+
event,
|
|
1935
1758
|
options,
|
|
1936
1759
|
state,
|
|
1937
1760
|
$session,
|
|
@@ -1942,11 +1765,9 @@ async function respond(incoming, options, state = {}) {
|
|
|
1942
1765
|
} catch (/** @type {unknown} */ e) {
|
|
1943
1766
|
const error = coalesce_to_error(e);
|
|
1944
1767
|
|
|
1945
|
-
return {
|
|
1946
|
-
status: 500
|
|
1947
|
-
|
|
1948
|
-
body: options.dev ? error.stack : error.message
|
|
1949
|
-
};
|
|
1768
|
+
return new Response(options.dev ? error.stack : error.message, {
|
|
1769
|
+
status: 500
|
|
1770
|
+
});
|
|
1950
1771
|
}
|
|
1951
1772
|
}
|
|
1952
1773
|
}
|
|
@@ -2108,7 +1929,7 @@ async function create_plugin(config, cwd) {
|
|
|
2108
1929
|
/** @type {import('types/internal').Hooks} */
|
|
2109
1930
|
const hooks = {
|
|
2110
1931
|
getSession: user_hooks.getSession || (() => ({})),
|
|
2111
|
-
handle: user_hooks.handle || (({
|
|
1932
|
+
handle: user_hooks.handle || (({ event, resolve }) => resolve(event)),
|
|
2112
1933
|
handleError:
|
|
2113
1934
|
user_hooks.handleError ||
|
|
2114
1935
|
(({ /** @type {Error & { frame?: string }} */ error }) => {
|
|
@@ -2155,12 +1976,11 @@ async function create_plugin(config, cwd) {
|
|
|
2155
1976
|
}
|
|
2156
1977
|
|
|
2157
1978
|
const rendered = await respond(
|
|
2158
|
-
{
|
|
2159
|
-
|
|
2160
|
-
headers: /** @type {import('types/helper').RequestHeaders} */ (req.headers),
|
|
1979
|
+
new Request(url.href, {
|
|
1980
|
+
headers: /** @type {Record<string, string>} */ (req.headers),
|
|
2161
1981
|
method: req.method,
|
|
2162
|
-
|
|
2163
|
-
},
|
|
1982
|
+
body
|
|
1983
|
+
}),
|
|
2164
1984
|
{
|
|
2165
1985
|
amp: config.kit.amp,
|
|
2166
1986
|
dev: true,
|
|
@@ -2169,9 +1989,20 @@ async function create_plugin(config, cwd) {
|
|
|
2169
1989
|
vite.ssrFixStacktrace(error);
|
|
2170
1990
|
return error.stack;
|
|
2171
1991
|
},
|
|
2172
|
-
handle_error: (error,
|
|
1992
|
+
handle_error: (error, event) => {
|
|
2173
1993
|
vite.ssrFixStacktrace(error);
|
|
2174
|
-
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
|
+
});
|
|
2175
2006
|
},
|
|
2176
2007
|
hooks,
|
|
2177
2008
|
hydrate: config.kit.hydrate,
|
|
@@ -2244,9 +2075,7 @@ async function create_plugin(config, cwd) {
|
|
|
2244
2075
|
);
|
|
2245
2076
|
|
|
2246
2077
|
if (rendered) {
|
|
2247
|
-
res
|
|
2248
|
-
if (rendered.body) res.write(rendered.body);
|
|
2249
|
-
res.end();
|
|
2078
|
+
setResponse(res, rendered);
|
|
2250
2079
|
} else {
|
|
2251
2080
|
not_found(res);
|
|
2252
2081
|
}
|