@sveltejs/kit 1.0.12 → 1.0.13
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/package.json +1 -1
- package/src/core/adapt/builder.js +1 -1
- package/src/core/{prerender → postbuild}/crawl.js +0 -0
- package/src/core/{prerender → postbuild}/entities.js +0 -0
- package/src/core/{prerender → postbuild}/fallback.js +10 -7
- package/src/core/postbuild/index.js +104 -0
- package/src/core/{prerender → postbuild}/prerender.js +32 -106
- package/src/core/{prerender → postbuild}/queue.js +0 -0
- package/src/core/sync/sync.js +10 -0
- package/src/core/sync/write_client_manifest.js +1 -1
- package/src/core/sync/write_server.js +89 -0
- package/src/core/utils.js +0 -9
- package/src/exports/vite/build/build_server.js +11 -163
- package/src/exports/vite/build/build_service_worker.js +3 -2
- package/src/exports/vite/build/utils.js +1 -0
- package/src/exports/vite/dev/index.js +72 -114
- package/src/exports/vite/index.js +26 -27
- package/src/exports/vite/preview/index.js +11 -12
- package/src/runtime/app/environment.js +1 -1
- package/src/runtime/app/paths.js +1 -1
- package/src/runtime/client/client.js +1 -1
- package/src/runtime/client/start.js +1 -2
- package/src/runtime/client/utils.js +1 -2
- package/src/runtime/control.js +23 -5
- package/src/runtime/server/ambient.d.ts +8 -0
- package/src/runtime/server/cookie.js +4 -5
- package/src/runtime/server/data/index.js +3 -2
- package/src/runtime/server/endpoint.js +5 -5
- package/src/runtime/server/fetch.js +11 -9
- package/src/runtime/server/index.js +54 -395
- package/src/runtime/server/page/csp.js +9 -11
- package/src/runtime/server/page/index.js +13 -8
- package/src/runtime/server/page/load_data.js +2 -3
- package/src/runtime/server/page/render.js +21 -19
- package/src/runtime/server/page/respond_with_error.js +20 -13
- package/src/runtime/server/page/types.d.ts +0 -1
- package/src/runtime/server/respond.js +419 -0
- package/src/runtime/server/utils.js +21 -4
- package/src/runtime/shared.js +28 -0
- package/types/internal.d.ts +23 -37
- package/src/runtime/env.js +0 -12
- package/src/runtime/paths.js +0 -11
|
@@ -1,405 +1,64 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
import { add_cookies_to_headers, get_cookies } from './cookie.js';
|
|
19
|
-
import { create_fetch } from './fetch.js';
|
|
20
|
-
import { Redirect } from '../control.js';
|
|
21
|
-
import {
|
|
22
|
-
validate_common_exports,
|
|
23
|
-
validate_page_server_exports,
|
|
24
|
-
validate_server_exports
|
|
25
|
-
} from '../../utils/exports.js';
|
|
26
|
-
import { error, json } from '../../exports/index.js';
|
|
27
|
-
|
|
28
|
-
/* global __SVELTEKIT_ADAPTER_NAME__ */
|
|
29
|
-
|
|
30
|
-
/** @type {import('types').RequiredResolveOptions['transformPageChunk']} */
|
|
31
|
-
const default_transform = ({ html }) => html;
|
|
32
|
-
|
|
33
|
-
/** @type {import('types').RequiredResolveOptions['filterSerializedResponseHeaders']} */
|
|
34
|
-
const default_filter = () => false;
|
|
35
|
-
|
|
36
|
-
/** @type {import('types').RequiredResolveOptions['preload']} */
|
|
37
|
-
const default_preload = ({ type }) => type === 'js' || type === 'css';
|
|
38
|
-
|
|
39
|
-
/** @type {import('types').Respond} */
|
|
40
|
-
export async function respond(request, options, state) {
|
|
41
|
-
/** URL but stripped from the potential `/__data.json` suffix and its search param */
|
|
42
|
-
let url = new URL(request.url);
|
|
43
|
-
|
|
44
|
-
if (options.csrf.check_origin) {
|
|
45
|
-
const forbidden =
|
|
46
|
-
request.method === 'POST' &&
|
|
47
|
-
request.headers.get('origin') !== url.origin &&
|
|
48
|
-
is_form_content_type(request);
|
|
49
|
-
|
|
50
|
-
if (forbidden) {
|
|
51
|
-
const csrf_error = error(403, `Cross-site ${request.method} form submissions are forbidden`);
|
|
52
|
-
if (request.headers.get('accept') === 'application/json') {
|
|
53
|
-
return json(csrf_error.body, { status: csrf_error.status });
|
|
54
|
-
}
|
|
55
|
-
return new Response(csrf_error.body.message, { status: csrf_error.status });
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
let decoded;
|
|
60
|
-
try {
|
|
61
|
-
decoded = decode_pathname(url.pathname);
|
|
62
|
-
} catch {
|
|
63
|
-
return new Response('Malformed URI', { status: 400 });
|
|
1
|
+
import { respond } from './respond.js';
|
|
2
|
+
import { set_private_env } from '../env-private.js';
|
|
3
|
+
import { set_public_env } from '../env-public.js';
|
|
4
|
+
import { options, get_hooks } from '__GENERATED__/server-internal.js';
|
|
5
|
+
|
|
6
|
+
export class Server {
|
|
7
|
+
/** @type {import('types').SSROptions} */
|
|
8
|
+
#options;
|
|
9
|
+
|
|
10
|
+
/** @type {import('types').SSRManifest} */
|
|
11
|
+
#manifest;
|
|
12
|
+
|
|
13
|
+
/** @param {import('types').SSRManifest} manifest */
|
|
14
|
+
constructor(manifest) {
|
|
15
|
+
/** @type {import('types').SSROptions} */
|
|
16
|
+
this.#options = options;
|
|
17
|
+
this.#manifest = manifest;
|
|
64
18
|
}
|
|
65
19
|
|
|
66
|
-
/**
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
if
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
for (const candidate of options.manifest._.routes) {
|
|
94
|
-
const match = candidate.pattern.exec(decoded);
|
|
95
|
-
if (!match) continue;
|
|
96
|
-
|
|
97
|
-
const matched = exec(match, candidate.params, matchers);
|
|
98
|
-
if (matched) {
|
|
99
|
-
route = candidate;
|
|
100
|
-
params = decode_params(matched);
|
|
101
|
-
break;
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
/** @type {import('types').TrailingSlash | void} */
|
|
107
|
-
let trailing_slash = undefined;
|
|
108
|
-
|
|
109
|
-
/** @type {Record<string, string>} */
|
|
110
|
-
const headers = {};
|
|
111
|
-
|
|
112
|
-
/** @type {import('types').RequestEvent} */
|
|
113
|
-
const event = {
|
|
114
|
-
// @ts-expect-error `cookies` and `fetch` need to be created after the `event` itself
|
|
115
|
-
cookies: null,
|
|
116
|
-
// @ts-expect-error
|
|
117
|
-
fetch: null,
|
|
118
|
-
getClientAddress:
|
|
119
|
-
state.getClientAddress ||
|
|
120
|
-
(() => {
|
|
121
|
-
throw new Error(
|
|
122
|
-
`${__SVELTEKIT_ADAPTER_NAME__} does not specify getClientAddress. Please raise an issue`
|
|
123
|
-
);
|
|
124
|
-
}),
|
|
125
|
-
locals: {},
|
|
126
|
-
params,
|
|
127
|
-
platform: state.platform,
|
|
128
|
-
request,
|
|
129
|
-
route: { id: route?.id ?? null },
|
|
130
|
-
setHeaders: (new_headers) => {
|
|
131
|
-
for (const key in new_headers) {
|
|
132
|
-
const lower = key.toLowerCase();
|
|
133
|
-
const value = new_headers[key];
|
|
134
|
-
|
|
135
|
-
if (lower === 'set-cookie') {
|
|
136
|
-
throw new Error(
|
|
137
|
-
`Use \`event.cookies.set(name, value, options)\` instead of \`event.setHeaders\` to set cookies`
|
|
138
|
-
);
|
|
139
|
-
} else if (lower in headers) {
|
|
140
|
-
throw new Error(`"${key}" header is already set`);
|
|
141
|
-
} else {
|
|
142
|
-
headers[lower] = value;
|
|
143
|
-
|
|
144
|
-
if (state.prerendering && lower === 'cache-control') {
|
|
145
|
-
state.prerendering.cache = /** @type {string} */ (value);
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
},
|
|
150
|
-
url,
|
|
151
|
-
isDataRequest: is_data_request
|
|
152
|
-
};
|
|
153
|
-
|
|
154
|
-
/** @type {import('types').RequiredResolveOptions} */
|
|
155
|
-
let resolve_opts = {
|
|
156
|
-
transformPageChunk: default_transform,
|
|
157
|
-
filterSerializedResponseHeaders: default_filter,
|
|
158
|
-
preload: default_preload
|
|
159
|
-
};
|
|
160
|
-
|
|
161
|
-
try {
|
|
162
|
-
// determine whether we need to redirect to add/remove a trailing slash
|
|
163
|
-
if (route && !is_data_request) {
|
|
164
|
-
if (route.page) {
|
|
165
|
-
const nodes = await Promise.all([
|
|
166
|
-
// we use == here rather than === because [undefined] serializes as "[null]"
|
|
167
|
-
...route.page.layouts.map((n) => (n == undefined ? n : options.manifest._.nodes[n]())),
|
|
168
|
-
options.manifest._.nodes[route.page.leaf]()
|
|
169
|
-
]);
|
|
170
|
-
|
|
171
|
-
if (DEV) {
|
|
172
|
-
const layouts = nodes.slice(0, -1);
|
|
173
|
-
const page = nodes.at(-1);
|
|
174
|
-
|
|
175
|
-
for (const layout of layouts) {
|
|
176
|
-
if (layout) {
|
|
177
|
-
validate_common_exports(layout.server, /** @type {string} */ (layout.server_id));
|
|
178
|
-
validate_common_exports(
|
|
179
|
-
layout.universal,
|
|
180
|
-
/** @type {string} */ (layout.universal_id)
|
|
181
|
-
);
|
|
182
|
-
}
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
if (page) {
|
|
186
|
-
validate_page_server_exports(page.server, /** @type {string} */ (page.server_id));
|
|
187
|
-
validate_common_exports(page.universal, /** @type {string} */ (page.universal_id));
|
|
188
|
-
}
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
trailing_slash = get_option(nodes, 'trailingSlash');
|
|
192
|
-
} else if (route.endpoint) {
|
|
193
|
-
const node = await route.endpoint();
|
|
194
|
-
trailing_slash = node.trailingSlash;
|
|
195
|
-
|
|
196
|
-
if (DEV) {
|
|
197
|
-
validate_server_exports(node, /** @type {string} */ (route.endpoint_id));
|
|
198
|
-
}
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
const normalized = normalize_path(url.pathname, trailing_slash ?? 'never');
|
|
202
|
-
|
|
203
|
-
if (normalized !== url.pathname && !state.prerendering?.fallback) {
|
|
204
|
-
return new Response(undefined, {
|
|
205
|
-
status: 301,
|
|
206
|
-
headers: {
|
|
207
|
-
'x-sveltekit-normalize': '1',
|
|
208
|
-
location:
|
|
209
|
-
// ensure paths starting with '//' are not treated as protocol-relative
|
|
210
|
-
(normalized.startsWith('//') ? url.origin + normalized : normalized) +
|
|
211
|
-
(url.search === '?' ? '' : url.search)
|
|
212
|
-
}
|
|
213
|
-
});
|
|
214
|
-
}
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
const { cookies, new_cookies, get_cookie_header } = get_cookies(
|
|
218
|
-
request,
|
|
219
|
-
url,
|
|
220
|
-
options.dev,
|
|
221
|
-
trailing_slash ?? 'never'
|
|
222
|
-
);
|
|
223
|
-
|
|
224
|
-
event.cookies = cookies;
|
|
225
|
-
event.fetch = create_fetch({ event, options, state, get_cookie_header });
|
|
226
|
-
|
|
227
|
-
if (state.prerendering && !state.prerendering.fallback) disable_search(url);
|
|
228
|
-
|
|
229
|
-
const response = await options.hooks.handle({
|
|
230
|
-
event,
|
|
231
|
-
resolve: (event, opts) =>
|
|
232
|
-
resolve(event, opts).then((response) => {
|
|
233
|
-
// add headers/cookies here, rather than inside `resolve`, so that we
|
|
234
|
-
// can do it once for all responses instead of once per `return`
|
|
235
|
-
for (const key in headers) {
|
|
236
|
-
const value = headers[key];
|
|
237
|
-
response.headers.set(key, /** @type {string} */ (value));
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
add_cookies_to_headers(response.headers, Object.values(new_cookies));
|
|
241
|
-
|
|
242
|
-
if (state.prerendering && event.route.id !== null) {
|
|
243
|
-
response.headers.set('x-sveltekit-routeid', encodeURI(event.route.id));
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
return response;
|
|
247
|
-
})
|
|
248
|
-
});
|
|
249
|
-
|
|
250
|
-
// respond with 304 if etag matches
|
|
251
|
-
if (response.status === 200 && response.headers.has('etag')) {
|
|
252
|
-
let if_none_match_value = request.headers.get('if-none-match');
|
|
253
|
-
|
|
254
|
-
// ignore W/ prefix https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/If-None-Match#directives
|
|
255
|
-
if (if_none_match_value?.startsWith('W/"')) {
|
|
256
|
-
if_none_match_value = if_none_match_value.substring(2);
|
|
257
|
-
}
|
|
258
|
-
|
|
259
|
-
const etag = /** @type {string} */ (response.headers.get('etag'));
|
|
260
|
-
|
|
261
|
-
if (if_none_match_value === etag) {
|
|
262
|
-
const headers = new Headers({ etag });
|
|
263
|
-
|
|
264
|
-
// https://datatracker.ietf.org/doc/html/rfc7232#section-4.1 + set-cookie
|
|
265
|
-
for (const key of [
|
|
266
|
-
'cache-control',
|
|
267
|
-
'content-location',
|
|
268
|
-
'date',
|
|
269
|
-
'expires',
|
|
270
|
-
'vary',
|
|
271
|
-
'set-cookie'
|
|
272
|
-
]) {
|
|
273
|
-
const value = response.headers.get(key);
|
|
274
|
-
if (value) headers.set(key, value);
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
return new Response(undefined, {
|
|
278
|
-
status: 304,
|
|
279
|
-
headers
|
|
280
|
-
});
|
|
281
|
-
}
|
|
282
|
-
}
|
|
283
|
-
|
|
284
|
-
// Edge case: If user does `return Response(30x)` in handle hook while processing a data request,
|
|
285
|
-
// we need to transform the redirect response to a corresponding JSON response.
|
|
286
|
-
if (is_data_request && response.status >= 300 && response.status <= 308) {
|
|
287
|
-
const location = response.headers.get('location');
|
|
288
|
-
if (location) {
|
|
289
|
-
return redirect_json_response(new Redirect(/** @type {any} */ (response.status), location));
|
|
290
|
-
}
|
|
291
|
-
}
|
|
292
|
-
|
|
293
|
-
return response;
|
|
294
|
-
} catch (error) {
|
|
295
|
-
if (error instanceof Redirect) {
|
|
296
|
-
if (is_data_request) {
|
|
297
|
-
return redirect_json_response(error);
|
|
298
|
-
} else {
|
|
299
|
-
return redirect_response(error.status, error.location);
|
|
300
|
-
}
|
|
20
|
+
/**
|
|
21
|
+
* @param {{
|
|
22
|
+
* env: Record<string, string>
|
|
23
|
+
* }} opts
|
|
24
|
+
*/
|
|
25
|
+
async init({ env }) {
|
|
26
|
+
// Take care: Some adapters may have to call `Server.init` per-request to set env vars,
|
|
27
|
+
// so anything that shouldn't be rerun should be wrapped in an `if` block to make sure it hasn't
|
|
28
|
+
// been done already.
|
|
29
|
+
const entries = Object.entries(env);
|
|
30
|
+
|
|
31
|
+
const prefix = this.#options.env_public_prefix;
|
|
32
|
+
const prv = Object.fromEntries(entries.filter(([k]) => !k.startsWith(prefix)));
|
|
33
|
+
const pub = Object.fromEntries(entries.filter(([k]) => k.startsWith(prefix)));
|
|
34
|
+
|
|
35
|
+
set_private_env(prv);
|
|
36
|
+
set_public_env(pub);
|
|
37
|
+
|
|
38
|
+
if (!this.#options.hooks) {
|
|
39
|
+
const module = await get_hooks();
|
|
40
|
+
|
|
41
|
+
this.#options.hooks = {
|
|
42
|
+
handle: module.handle || (({ event, resolve }) => resolve(event)),
|
|
43
|
+
// @ts-expect-error
|
|
44
|
+
handleError: module.handleError || (({ error }) => console.error(error?.stack)),
|
|
45
|
+
handleFetch: module.handleFetch || (({ request, fetch }) => fetch(request))
|
|
46
|
+
};
|
|
301
47
|
}
|
|
302
|
-
return await handle_fatal_error(event, options, error);
|
|
303
48
|
}
|
|
304
49
|
|
|
305
50
|
/**
|
|
306
|
-
*
|
|
307
|
-
* @param {import('types').
|
|
308
|
-
* @param {import('types').ResolveOptions} [opts]
|
|
51
|
+
* @param {Request} request
|
|
52
|
+
* @param {import('types').RequestOptions} options
|
|
309
53
|
*/
|
|
310
|
-
async
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
);
|
|
317
|
-
}
|
|
318
|
-
|
|
319
|
-
resolve_opts = {
|
|
320
|
-
transformPageChunk: opts.transformPageChunk || default_transform,
|
|
321
|
-
filterSerializedResponseHeaders: opts.filterSerializedResponseHeaders || default_filter,
|
|
322
|
-
preload: opts.preload || default_preload
|
|
323
|
-
};
|
|
324
|
-
}
|
|
325
|
-
|
|
326
|
-
if (state.prerendering?.fallback) {
|
|
327
|
-
return await render_response({
|
|
328
|
-
event,
|
|
329
|
-
options,
|
|
330
|
-
state,
|
|
331
|
-
page_config: { ssr: false, csr: true },
|
|
332
|
-
status: 200,
|
|
333
|
-
error: null,
|
|
334
|
-
branch: [],
|
|
335
|
-
fetched: [],
|
|
336
|
-
resolve_opts
|
|
337
|
-
});
|
|
338
|
-
}
|
|
339
|
-
|
|
340
|
-
if (route) {
|
|
341
|
-
/** @type {Response} */
|
|
342
|
-
let response;
|
|
343
|
-
|
|
344
|
-
if (is_data_request) {
|
|
345
|
-
response = await render_data(
|
|
346
|
-
event,
|
|
347
|
-
route,
|
|
348
|
-
options,
|
|
349
|
-
state,
|
|
350
|
-
invalidated_data_nodes,
|
|
351
|
-
trailing_slash ?? 'never'
|
|
352
|
-
);
|
|
353
|
-
} else if (route.endpoint && (!route.page || is_endpoint_request(event))) {
|
|
354
|
-
response = await render_endpoint(event, await route.endpoint(), state);
|
|
355
|
-
} else if (route.page) {
|
|
356
|
-
response = await render_page(event, route, route.page, options, state, resolve_opts);
|
|
357
|
-
} else {
|
|
358
|
-
// a route will always have a page or an endpoint, but TypeScript
|
|
359
|
-
// doesn't know that
|
|
360
|
-
throw new Error('This should never happen');
|
|
361
|
-
}
|
|
362
|
-
|
|
363
|
-
return response;
|
|
364
|
-
}
|
|
365
|
-
|
|
366
|
-
if (state.initiator === GENERIC_ERROR) {
|
|
367
|
-
return new Response('Internal Server Error', {
|
|
368
|
-
status: 500
|
|
369
|
-
});
|
|
370
|
-
}
|
|
371
|
-
|
|
372
|
-
// if this request came direct from the user, rather than
|
|
373
|
-
// via a `fetch` in a `load`, render a 404 page
|
|
374
|
-
if (!state.initiator) {
|
|
375
|
-
return await respond_with_error({
|
|
376
|
-
event,
|
|
377
|
-
options,
|
|
378
|
-
state,
|
|
379
|
-
status: 404,
|
|
380
|
-
error: new Error(`Not found: ${event.url.pathname}`),
|
|
381
|
-
resolve_opts
|
|
382
|
-
});
|
|
383
|
-
}
|
|
384
|
-
|
|
385
|
-
if (state.prerendering) {
|
|
386
|
-
return new Response('not found', { status: 404 });
|
|
387
|
-
}
|
|
388
|
-
|
|
389
|
-
// we can't load the endpoint from our own manifest,
|
|
390
|
-
// so we need to make an actual HTTP request
|
|
391
|
-
return await fetch(request);
|
|
392
|
-
} catch (error) {
|
|
393
|
-
// HttpError from endpoint can end up here - TODO should it be handled there instead?
|
|
394
|
-
return await handle_fatal_error(event, options, error);
|
|
395
|
-
} finally {
|
|
396
|
-
event.cookies.set = () => {
|
|
397
|
-
throw new Error('Cannot use `cookies.set(...)` after the response has been generated');
|
|
398
|
-
};
|
|
399
|
-
|
|
400
|
-
event.setHeaders = () => {
|
|
401
|
-
throw new Error('Cannot use `setHeaders(...)` after the response has been generated');
|
|
402
|
-
};
|
|
54
|
+
async respond(request, options) {
|
|
55
|
+
// TODO this should probably have been removed for 1.0 — i think we can get rid of it?
|
|
56
|
+
if (!(request instanceof Request)) {
|
|
57
|
+
throw new Error(
|
|
58
|
+
'The first argument to server.respond must be a Request object. See https://github.com/sveltejs/kit/pull/3384 for details'
|
|
59
|
+
);
|
|
403
60
|
}
|
|
61
|
+
|
|
62
|
+
return respond(request, this.#options, this.#manifest, options);
|
|
404
63
|
}
|
|
405
64
|
}
|
|
@@ -50,15 +50,14 @@ class BaseProvider {
|
|
|
50
50
|
* @param {boolean} use_hashes
|
|
51
51
|
* @param {import('types').CspDirectives} directives
|
|
52
52
|
* @param {string} nonce
|
|
53
|
-
* @param {boolean} dev
|
|
54
53
|
*/
|
|
55
|
-
constructor(use_hashes, directives, nonce
|
|
54
|
+
constructor(use_hashes, directives, nonce) {
|
|
56
55
|
this.#use_hashes = use_hashes;
|
|
57
|
-
this.#directives =
|
|
56
|
+
this.#directives = __SVELTEKIT_DEV__ ? { ...directives } : directives; // clone in dev so we can safely mutate
|
|
58
57
|
|
|
59
58
|
const d = this.#directives;
|
|
60
59
|
|
|
61
|
-
if (
|
|
60
|
+
if (__SVELTEKIT_DEV__) {
|
|
62
61
|
// remove strict-dynamic in dev...
|
|
63
62
|
// TODO reinstate this if we can figure out how to make strict-dynamic work
|
|
64
63
|
// if (d['default-src']) {
|
|
@@ -90,7 +89,7 @@ class BaseProvider {
|
|
|
90
89
|
effective_script_src.filter((value) => value !== 'unsafe-inline').length > 0;
|
|
91
90
|
|
|
92
91
|
this.#style_needs_csp =
|
|
93
|
-
!
|
|
92
|
+
!__SVELTEKIT_DEV__ &&
|
|
94
93
|
!!effective_style_src &&
|
|
95
94
|
effective_style_src.filter((value) => value !== 'unsafe-inline').length > 0;
|
|
96
95
|
|
|
@@ -189,10 +188,9 @@ class CspReportOnlyProvider extends BaseProvider {
|
|
|
189
188
|
* @param {boolean} use_hashes
|
|
190
189
|
* @param {import('types').CspDirectives} directives
|
|
191
190
|
* @param {string} nonce
|
|
192
|
-
* @param {boolean} dev
|
|
193
191
|
*/
|
|
194
|
-
constructor(use_hashes, directives, nonce
|
|
195
|
-
super(use_hashes, directives, nonce
|
|
192
|
+
constructor(use_hashes, directives, nonce) {
|
|
193
|
+
super(use_hashes, directives, nonce);
|
|
196
194
|
|
|
197
195
|
if (Object.values(directives).filter((v) => !!v).length > 0) {
|
|
198
196
|
// If we're generating content-security-policy-report-only,
|
|
@@ -223,10 +221,10 @@ export class Csp {
|
|
|
223
221
|
* @param {import('./types').CspConfig} config
|
|
224
222
|
* @param {import('./types').CspOpts} opts
|
|
225
223
|
*/
|
|
226
|
-
constructor({ mode, directives, reportOnly }, { prerender
|
|
224
|
+
constructor({ mode, directives, reportOnly }, { prerender }) {
|
|
227
225
|
const use_hashes = mode === 'hash' || (mode === 'auto' && prerender);
|
|
228
|
-
this.csp_provider = new CspProvider(use_hashes, directives, this.nonce
|
|
229
|
-
this.report_only_provider = new CspReportOnlyProvider(use_hashes, reportOnly, this.nonce
|
|
226
|
+
this.csp_provider = new CspProvider(use_hashes, directives, this.nonce);
|
|
227
|
+
this.report_only_provider = new CspReportOnlyProvider(use_hashes, reportOnly, this.nonce);
|
|
230
228
|
}
|
|
231
229
|
|
|
232
230
|
get script_needs_nonce() {
|
|
@@ -24,11 +24,12 @@ import { respond_with_error } from './respond_with_error.js';
|
|
|
24
24
|
* @param {import('types').SSRRoute} route
|
|
25
25
|
* @param {import('types').PageNodeIndexes} page
|
|
26
26
|
* @param {import('types').SSROptions} options
|
|
27
|
+
* @param {import('types').SSRManifest} manifest
|
|
27
28
|
* @param {import('types').SSRState} state
|
|
28
29
|
* @param {import('types').RequiredResolveOptions} resolve_opts
|
|
29
30
|
* @returns {Promise<Response>}
|
|
30
31
|
*/
|
|
31
|
-
export async function render_page(event, route, page, options, state, resolve_opts) {
|
|
32
|
+
export async function render_page(event, route, page, options, manifest, state, resolve_opts) {
|
|
32
33
|
if (state.initiator === route) {
|
|
33
34
|
// infinite request cycle detected
|
|
34
35
|
return new Response(`Not found: ${event.url.pathname}`, {
|
|
@@ -39,15 +40,15 @@ export async function render_page(event, route, page, options, state, resolve_op
|
|
|
39
40
|
state.initiator = route;
|
|
40
41
|
|
|
41
42
|
if (is_action_json_request(event)) {
|
|
42
|
-
const node = await
|
|
43
|
+
const node = await manifest._.nodes[page.leaf]();
|
|
43
44
|
return handle_action_json_request(event, options, node?.server);
|
|
44
45
|
}
|
|
45
46
|
|
|
46
47
|
try {
|
|
47
48
|
const nodes = await Promise.all([
|
|
48
49
|
// we use == here rather than === because [undefined] serializes as "[null]"
|
|
49
|
-
...page.layouts.map((n) => (n == undefined ? n :
|
|
50
|
-
|
|
50
|
+
...page.layouts.map((n) => (n == undefined ? n : manifest._.nodes[n]())),
|
|
51
|
+
manifest._.nodes[page.leaf]()
|
|
51
52
|
]);
|
|
52
53
|
|
|
53
54
|
const leaf_node = /** @type {import('types').SSRNode} */ (nodes.at(-1));
|
|
@@ -105,6 +106,7 @@ export async function render_page(event, route, page, options, state, resolve_op
|
|
|
105
106
|
error: null,
|
|
106
107
|
event,
|
|
107
108
|
options,
|
|
109
|
+
manifest,
|
|
108
110
|
state,
|
|
109
111
|
resolve_opts
|
|
110
112
|
});
|
|
@@ -135,6 +137,7 @@ export async function render_page(event, route, page, options, state, resolve_op
|
|
|
135
137
|
error: null,
|
|
136
138
|
event,
|
|
137
139
|
options,
|
|
140
|
+
manifest,
|
|
138
141
|
state,
|
|
139
142
|
resolve_opts
|
|
140
143
|
});
|
|
@@ -163,7 +166,6 @@ export async function render_page(event, route, page, options, state, resolve_op
|
|
|
163
166
|
|
|
164
167
|
return await load_server_data({
|
|
165
168
|
event,
|
|
166
|
-
options,
|
|
167
169
|
state,
|
|
168
170
|
node,
|
|
169
171
|
parent: async () => {
|
|
@@ -251,7 +253,7 @@ export async function render_page(event, route, page, options, state, resolve_op
|
|
|
251
253
|
while (i--) {
|
|
252
254
|
if (page.errors[i]) {
|
|
253
255
|
const index = /** @type {number} */ (page.errors[i]);
|
|
254
|
-
const node = await
|
|
256
|
+
const node = await manifest._.nodes[index]();
|
|
255
257
|
|
|
256
258
|
let j = i;
|
|
257
259
|
while (!branch[j]) j -= 1;
|
|
@@ -259,6 +261,7 @@ export async function render_page(event, route, page, options, state, resolve_op
|
|
|
259
261
|
return await render_response({
|
|
260
262
|
event,
|
|
261
263
|
options,
|
|
264
|
+
manifest,
|
|
262
265
|
state,
|
|
263
266
|
resolve_opts,
|
|
264
267
|
page_config: { ssr: true, csr: true },
|
|
@@ -299,6 +302,7 @@ export async function render_page(event, route, page, options, state, resolve_op
|
|
|
299
302
|
return await render_response({
|
|
300
303
|
event,
|
|
301
304
|
options,
|
|
305
|
+
manifest,
|
|
302
306
|
state,
|
|
303
307
|
resolve_opts,
|
|
304
308
|
page_config: {
|
|
@@ -311,15 +315,16 @@ export async function render_page(event, route, page, options, state, resolve_op
|
|
|
311
315
|
action_result,
|
|
312
316
|
fetched
|
|
313
317
|
});
|
|
314
|
-
} catch (
|
|
318
|
+
} catch (e) {
|
|
315
319
|
// if we end up here, it means the data loaded successfull
|
|
316
320
|
// but the page failed to render, or that a prerendering error occurred
|
|
317
321
|
return await respond_with_error({
|
|
318
322
|
event,
|
|
319
323
|
options,
|
|
324
|
+
manifest,
|
|
320
325
|
state,
|
|
321
326
|
status: 500,
|
|
322
|
-
error,
|
|
327
|
+
error: e,
|
|
323
328
|
resolve_opts
|
|
324
329
|
});
|
|
325
330
|
}
|
|
@@ -5,14 +5,13 @@ import { unwrap_promises } from '../../../utils/promises.js';
|
|
|
5
5
|
* Calls the user's server `load` function.
|
|
6
6
|
* @param {{
|
|
7
7
|
* event: import('types').RequestEvent;
|
|
8
|
-
* options: import('types').SSROptions;
|
|
9
8
|
* state: import('types').SSRState;
|
|
10
9
|
* node: import('types').SSRNode | undefined;
|
|
11
10
|
* parent: () => Promise<Record<string, any>>;
|
|
12
11
|
* }} opts
|
|
13
12
|
* @returns {Promise<import('types').ServerDataNode | null>}
|
|
14
13
|
*/
|
|
15
|
-
export async function load_server_data({ event,
|
|
14
|
+
export async function load_server_data({ event, state, node, parent }) {
|
|
16
15
|
if (!node?.server) return null;
|
|
17
16
|
|
|
18
17
|
const uses = {
|
|
@@ -66,7 +65,7 @@ export async function load_server_data({ event, options, state, node, parent })
|
|
|
66
65
|
});
|
|
67
66
|
|
|
68
67
|
const data = result ? await unwrap_promises(result) : null;
|
|
69
|
-
if (
|
|
68
|
+
if (__SVELTEKIT_DEV__) {
|
|
70
69
|
validate_load_response(data, /** @type {string} */ (event.route.id));
|
|
71
70
|
}
|
|
72
71
|
|