@sveltejs/kit 2.50.1 → 2.51.0
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 +4 -4
- package/src/core/postbuild/crawl.js +3 -3
- package/src/core/sync/write_tsconfig.js +7 -5
- package/src/exports/public.d.ts +14 -1
- package/src/exports/vite/build/build_server.js +116 -80
- package/src/exports/vite/index.js +4 -6
- package/src/exports/vite/static_analysis/utils.js +17 -0
- package/src/runtime/app/environment/index.js +1 -5
- package/src/runtime/app/server/remote/command.js +3 -1
- package/src/runtime/app/server/remote/form.js +1 -2
- package/src/runtime/app/server/remote/prerender.js +1 -1
- package/src/runtime/app/server/remote/query.js +39 -18
- package/src/runtime/app/server/remote/shared.js +4 -5
- package/src/runtime/client/client.js +22 -19
- package/src/runtime/server/fetch.js +6 -2
- package/src/runtime/server/page/csp.js +66 -28
- package/src/runtime/server/page/index.js +7 -2
- package/src/runtime/server/page/render.js +112 -44
- package/src/runtime/server/remote.js +4 -15
- package/src/types/internal.d.ts +13 -7
- package/src/utils/css.js +210 -0
- package/src/utils/routing.js +6 -2
- package/src/version.js +1 -1
- package/types/index.d.ts +22 -3
- package/types/index.d.ts.map +1 -1
|
@@ -605,7 +605,8 @@ async function initialize(result, target, hydrate) {
|
|
|
605
605
|
to: {
|
|
606
606
|
params: current.params,
|
|
607
607
|
route: { id: current.route?.id ?? null },
|
|
608
|
-
url: new URL(location.href)
|
|
608
|
+
url: new URL(location.href),
|
|
609
|
+
scroll: scroll_positions[current_history_index] ?? scroll_state()
|
|
609
610
|
},
|
|
610
611
|
willUnload: false,
|
|
611
612
|
type: 'enter',
|
|
@@ -1463,12 +1464,13 @@ function get_page_key(url) {
|
|
|
1463
1464
|
* intent?: import('./types.js').NavigationIntent;
|
|
1464
1465
|
* delta?: number;
|
|
1465
1466
|
* event?: PopStateEvent | MouseEvent;
|
|
1467
|
+
* scroll?: { x: number, y: number };
|
|
1466
1468
|
* }} opts
|
|
1467
1469
|
*/
|
|
1468
|
-
function _before_navigate({ url, type, intent, delta, event }) {
|
|
1470
|
+
function _before_navigate({ url, type, intent, delta, event, scroll }) {
|
|
1469
1471
|
let should_block = false;
|
|
1470
1472
|
|
|
1471
|
-
const nav = create_navigation(current, intent, url, type);
|
|
1473
|
+
const nav = create_navigation(current, intent, url, type, scroll ?? null);
|
|
1472
1474
|
|
|
1473
1475
|
if (delta !== undefined) {
|
|
1474
1476
|
nav.navigation.delta = delta;
|
|
@@ -1543,6 +1545,7 @@ async function navigate({
|
|
|
1543
1545
|
type,
|
|
1544
1546
|
delta: popped?.delta,
|
|
1545
1547
|
intent,
|
|
1548
|
+
scroll: popped?.scroll,
|
|
1546
1549
|
// @ts-ignore
|
|
1547
1550
|
event
|
|
1548
1551
|
});
|
|
@@ -1808,6 +1811,11 @@ async function navigate({
|
|
|
1808
1811
|
|
|
1809
1812
|
nav.fulfil(undefined);
|
|
1810
1813
|
|
|
1814
|
+
// Update to.scroll to the actual scroll position after navigation completed
|
|
1815
|
+
if (nav.navigation.to) {
|
|
1816
|
+
nav.navigation.to.scroll = scroll_state();
|
|
1817
|
+
}
|
|
1818
|
+
|
|
1811
1819
|
after_navigate_callbacks.forEach((fn) =>
|
|
1812
1820
|
fn(/** @type {import('@sveltejs/kit').AfterNavigate} */ (nav.navigation))
|
|
1813
1821
|
);
|
|
@@ -3013,20 +3021,12 @@ function reset_focus(url, scroll = null) {
|
|
|
3013
3021
|
const history_state = history.state;
|
|
3014
3022
|
|
|
3015
3023
|
resetting_focus = true;
|
|
3016
|
-
location.replace(`#${id}
|
|
3024
|
+
location.replace(new URL(`#${id}`, location.href));
|
|
3017
3025
|
|
|
3018
|
-
//
|
|
3019
|
-
//
|
|
3020
|
-
//
|
|
3021
|
-
|
|
3022
|
-
if (app.hash) {
|
|
3023
|
-
location.replace(url.hash);
|
|
3024
|
-
}
|
|
3025
|
-
|
|
3026
|
-
// but Firefox has a bug that sets the history state to `null` so we
|
|
3027
|
-
// need to restore it after.
|
|
3028
|
-
// See https://bugzilla.mozilla.org/show_bug.cgi?id=1199924
|
|
3029
|
-
history.replaceState(history_state, '', url.hash);
|
|
3026
|
+
// Firefox has a bug that sets the history state to `null` so we need to
|
|
3027
|
+
// restore it after. See https://bugzilla.mozilla.org/show_bug.cgi?id=1199924
|
|
3028
|
+
// This is also needed to restore the original hash if we're using hash routing
|
|
3029
|
+
history.replaceState(history_state, '', url);
|
|
3030
3030
|
|
|
3031
3031
|
// Scroll management has already happened earlier so we need to restore
|
|
3032
3032
|
// the scroll position after setting the sequential focus navigation starting point
|
|
@@ -3102,8 +3102,9 @@ function reset_focus(url, scroll = null) {
|
|
|
3102
3102
|
* @param {import('./types.js').NavigationIntent | undefined} intent
|
|
3103
3103
|
* @param {URL | null} url
|
|
3104
3104
|
* @param {T} type
|
|
3105
|
+
* @param {{ x: number, y: number } | null} [target_scroll] The scroll position for the target (for popstate navigations)
|
|
3105
3106
|
*/
|
|
3106
|
-
function create_navigation(current, intent, url, type) {
|
|
3107
|
+
function create_navigation(current, intent, url, type, target_scroll = null) {
|
|
3107
3108
|
/** @type {(value: any) => void} */
|
|
3108
3109
|
let fulfil;
|
|
3109
3110
|
|
|
@@ -3123,12 +3124,14 @@ function create_navigation(current, intent, url, type) {
|
|
|
3123
3124
|
from: {
|
|
3124
3125
|
params: current.params,
|
|
3125
3126
|
route: { id: current.route?.id ?? null },
|
|
3126
|
-
url: current.url
|
|
3127
|
+
url: current.url,
|
|
3128
|
+
scroll: scroll_state()
|
|
3127
3129
|
},
|
|
3128
3130
|
to: url && {
|
|
3129
3131
|
params: intent?.params ?? null,
|
|
3130
3132
|
route: { id: intent?.route?.id ?? null },
|
|
3131
|
-
url
|
|
3133
|
+
url,
|
|
3134
|
+
scroll: target_scroll
|
|
3132
3135
|
},
|
|
3133
3136
|
willUnload: !intent,
|
|
3134
3137
|
type,
|
|
@@ -55,7 +55,12 @@ export function create_fetch({ event, options, manifest, state, get_cookie_heade
|
|
|
55
55
|
request.headers.delete('origin');
|
|
56
56
|
}
|
|
57
57
|
|
|
58
|
-
|
|
58
|
+
const decoded = decodeURIComponent(url.pathname);
|
|
59
|
+
|
|
60
|
+
if (
|
|
61
|
+
url.origin !== event.url.origin ||
|
|
62
|
+
(paths.base && decoded !== paths.base && !decoded.startsWith(`${paths.base}/`))
|
|
63
|
+
) {
|
|
59
64
|
// Allow cookie passthrough for "credentials: same-origin" and "credentials: include"
|
|
60
65
|
// if SvelteKit is serving my.domain.com:
|
|
61
66
|
// - domain.com WILL NOT receive cookies
|
|
@@ -77,7 +82,6 @@ export function create_fetch({ event, options, manifest, state, get_cookie_heade
|
|
|
77
82
|
// handle fetch requests for static assets. e.g. prebaked data, etc.
|
|
78
83
|
// we need to support everything the browser's fetch supports
|
|
79
84
|
const prefix = paths.assets || paths.base;
|
|
80
|
-
const decoded = decodeURIComponent(url.pathname);
|
|
81
85
|
const filename = (
|
|
82
86
|
decoded.startsWith(prefix) ? decoded.slice(prefix.length) : decoded
|
|
83
87
|
).slice(1);
|
|
@@ -53,21 +53,30 @@ class BaseProvider {
|
|
|
53
53
|
/** @type {import('types').CspDirectives} */
|
|
54
54
|
#directives;
|
|
55
55
|
|
|
56
|
-
/** @type {import('types').Csp.Source
|
|
56
|
+
/** @type {Set<import('types').Csp.Source>} */
|
|
57
57
|
#script_src;
|
|
58
58
|
|
|
59
|
-
/** @type {import('types').Csp.Source
|
|
59
|
+
/** @type {Set<import('types').Csp.Source>} */
|
|
60
60
|
#script_src_elem;
|
|
61
61
|
|
|
62
|
-
/** @type {import('types').Csp.Source
|
|
62
|
+
/** @type {Set<import('types').Csp.Source>} */
|
|
63
63
|
#style_src;
|
|
64
64
|
|
|
65
|
-
/** @type {import('types').Csp.Source
|
|
65
|
+
/** @type {Set<import('types').Csp.Source>} */
|
|
66
66
|
#style_src_attr;
|
|
67
67
|
|
|
68
|
-
/** @type {import('types').Csp.Source
|
|
68
|
+
/** @type {Set<import('types').Csp.Source>} */
|
|
69
69
|
#style_src_elem;
|
|
70
70
|
|
|
71
|
+
/** @type {boolean} */
|
|
72
|
+
script_needs_nonce;
|
|
73
|
+
|
|
74
|
+
/** @type {boolean} */
|
|
75
|
+
style_needs_nonce;
|
|
76
|
+
|
|
77
|
+
/** @type {boolean} */
|
|
78
|
+
script_needs_hash;
|
|
79
|
+
|
|
71
80
|
/** @type {string} */
|
|
72
81
|
#nonce;
|
|
73
82
|
|
|
@@ -82,11 +91,11 @@ class BaseProvider {
|
|
|
82
91
|
|
|
83
92
|
const d = this.#directives;
|
|
84
93
|
|
|
85
|
-
this.#script_src =
|
|
86
|
-
this.#script_src_elem =
|
|
87
|
-
this.#style_src =
|
|
88
|
-
this.#style_src_attr =
|
|
89
|
-
this.#style_src_elem =
|
|
94
|
+
this.#script_src = new Set();
|
|
95
|
+
this.#script_src_elem = new Set();
|
|
96
|
+
this.#style_src = new Set();
|
|
97
|
+
this.#style_src_attr = new Set();
|
|
98
|
+
this.#style_src_elem = new Set();
|
|
90
99
|
|
|
91
100
|
const effective_script_src = d['script-src'] || d['default-src'];
|
|
92
101
|
const script_src_elem = d['script-src-elem'];
|
|
@@ -138,14 +147,20 @@ class BaseProvider {
|
|
|
138
147
|
}
|
|
139
148
|
|
|
140
149
|
/** @param {(import('types').Csp.Source | import('types').Csp.ActionSource)[] | undefined} directive */
|
|
141
|
-
const
|
|
150
|
+
const style_needs_csp = (directive) =>
|
|
142
151
|
!!directive && !directive.some((value) => value === 'unsafe-inline');
|
|
143
152
|
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
153
|
+
/** @param {(import('types').Csp.Source | import('types').Csp.ActionSource)[] | undefined} directive */
|
|
154
|
+
const script_needs_csp = (directive) =>
|
|
155
|
+
!!directive &&
|
|
156
|
+
(!directive.some((value) => value === 'unsafe-inline') ||
|
|
157
|
+
directive.some((value) => value === 'strict-dynamic'));
|
|
158
|
+
|
|
159
|
+
this.#script_src_needs_csp = script_needs_csp(effective_script_src);
|
|
160
|
+
this.#script_src_elem_needs_csp = script_needs_csp(script_src_elem);
|
|
161
|
+
this.#style_src_needs_csp = style_needs_csp(effective_style_src);
|
|
162
|
+
this.#style_src_attr_needs_csp = style_needs_csp(style_src_attr);
|
|
163
|
+
this.#style_src_elem_needs_csp = style_needs_csp(style_src_elem);
|
|
149
164
|
|
|
150
165
|
this.#script_needs_csp = this.#script_src_needs_csp || this.#script_src_elem_needs_csp;
|
|
151
166
|
this.#style_needs_csp =
|
|
@@ -156,6 +171,7 @@ class BaseProvider {
|
|
|
156
171
|
|
|
157
172
|
this.script_needs_nonce = this.#script_needs_csp && !this.#use_hashes;
|
|
158
173
|
this.style_needs_nonce = this.#style_needs_csp && !this.#use_hashes;
|
|
174
|
+
this.script_needs_hash = this.#script_needs_csp && this.#use_hashes;
|
|
159
175
|
|
|
160
176
|
this.#nonce = nonce;
|
|
161
177
|
}
|
|
@@ -168,11 +184,23 @@ class BaseProvider {
|
|
|
168
184
|
const source = this.#use_hashes ? `sha256-${sha256(content)}` : `nonce-${this.#nonce}`;
|
|
169
185
|
|
|
170
186
|
if (this.#script_src_needs_csp) {
|
|
171
|
-
this.#script_src.
|
|
187
|
+
this.#script_src.add(source);
|
|
172
188
|
}
|
|
173
189
|
|
|
174
190
|
if (this.#script_src_elem_needs_csp) {
|
|
175
|
-
this.#script_src_elem.
|
|
191
|
+
this.#script_src_elem.add(source);
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/** @param {`sha256-${string}`[]} hashes */
|
|
196
|
+
add_script_hashes(hashes) {
|
|
197
|
+
for (const hash of hashes) {
|
|
198
|
+
if (this.#script_src_needs_csp) {
|
|
199
|
+
this.#script_src.add(hash);
|
|
200
|
+
}
|
|
201
|
+
if (this.#script_src_elem_needs_csp) {
|
|
202
|
+
this.#script_src_elem.add(hash);
|
|
203
|
+
}
|
|
176
204
|
}
|
|
177
205
|
}
|
|
178
206
|
|
|
@@ -184,11 +212,11 @@ class BaseProvider {
|
|
|
184
212
|
const source = this.#use_hashes ? `sha256-${sha256(content)}` : `nonce-${this.#nonce}`;
|
|
185
213
|
|
|
186
214
|
if (this.#style_src_needs_csp) {
|
|
187
|
-
this.#style_src.
|
|
215
|
+
this.#style_src.add(source);
|
|
188
216
|
}
|
|
189
217
|
|
|
190
218
|
if (this.#style_src_attr_needs_csp) {
|
|
191
|
-
this.#style_src_attr.
|
|
219
|
+
this.#style_src_attr.add(source);
|
|
192
220
|
}
|
|
193
221
|
|
|
194
222
|
if (this.#style_src_elem_needs_csp) {
|
|
@@ -201,13 +229,13 @@ class BaseProvider {
|
|
|
201
229
|
if (
|
|
202
230
|
d['style-src-elem'] &&
|
|
203
231
|
!d['style-src-elem'].includes(sha256_empty_comment_hash) &&
|
|
204
|
-
!this.#style_src_elem.
|
|
232
|
+
!this.#style_src_elem.has(sha256_empty_comment_hash)
|
|
205
233
|
) {
|
|
206
|
-
this.#style_src_elem.
|
|
234
|
+
this.#style_src_elem.add(sha256_empty_comment_hash);
|
|
207
235
|
}
|
|
208
236
|
|
|
209
237
|
if (source !== sha256_empty_comment_hash) {
|
|
210
|
-
this.#style_src_elem.
|
|
238
|
+
this.#style_src_elem.add(source);
|
|
211
239
|
}
|
|
212
240
|
}
|
|
213
241
|
}
|
|
@@ -224,35 +252,35 @@ class BaseProvider {
|
|
|
224
252
|
|
|
225
253
|
const directives = { ...this.#directives };
|
|
226
254
|
|
|
227
|
-
if (this.#style_src.
|
|
255
|
+
if (this.#style_src.size > 0) {
|
|
228
256
|
directives['style-src'] = [
|
|
229
257
|
...(directives['style-src'] || directives['default-src'] || []),
|
|
230
258
|
...this.#style_src
|
|
231
259
|
];
|
|
232
260
|
}
|
|
233
261
|
|
|
234
|
-
if (this.#style_src_attr.
|
|
262
|
+
if (this.#style_src_attr.size > 0) {
|
|
235
263
|
directives['style-src-attr'] = [
|
|
236
264
|
...(directives['style-src-attr'] || []),
|
|
237
265
|
...this.#style_src_attr
|
|
238
266
|
];
|
|
239
267
|
}
|
|
240
268
|
|
|
241
|
-
if (this.#style_src_elem.
|
|
269
|
+
if (this.#style_src_elem.size > 0) {
|
|
242
270
|
directives['style-src-elem'] = [
|
|
243
271
|
...(directives['style-src-elem'] || []),
|
|
244
272
|
...this.#style_src_elem
|
|
245
273
|
];
|
|
246
274
|
}
|
|
247
275
|
|
|
248
|
-
if (this.#script_src.
|
|
276
|
+
if (this.#script_src.size > 0) {
|
|
249
277
|
directives['script-src'] = [
|
|
250
278
|
...(directives['script-src'] || directives['default-src'] || []),
|
|
251
279
|
...this.#script_src
|
|
252
280
|
];
|
|
253
281
|
}
|
|
254
282
|
|
|
255
|
-
if (this.#script_src_elem.
|
|
283
|
+
if (this.#script_src_elem.size > 0) {
|
|
256
284
|
directives['script-src-elem'] = [
|
|
257
285
|
...(directives['script-src-elem'] || []),
|
|
258
286
|
...this.#script_src_elem
|
|
@@ -345,6 +373,10 @@ export class Csp {
|
|
|
345
373
|
this.report_only_provider = new CspReportOnlyProvider(use_hashes, reportOnly, this.nonce);
|
|
346
374
|
}
|
|
347
375
|
|
|
376
|
+
get script_needs_hash() {
|
|
377
|
+
return this.csp_provider.script_needs_hash || this.report_only_provider.script_needs_hash;
|
|
378
|
+
}
|
|
379
|
+
|
|
348
380
|
get script_needs_nonce() {
|
|
349
381
|
return this.csp_provider.script_needs_nonce || this.report_only_provider.script_needs_nonce;
|
|
350
382
|
}
|
|
@@ -359,6 +391,12 @@ export class Csp {
|
|
|
359
391
|
this.report_only_provider.add_script(content);
|
|
360
392
|
}
|
|
361
393
|
|
|
394
|
+
/** @param {`sha256-${string}`[]} hashes */
|
|
395
|
+
add_script_hashes(hashes) {
|
|
396
|
+
this.csp_provider.add_script_hashes(hashes);
|
|
397
|
+
this.report_only_provider.add_script_hashes(hashes);
|
|
398
|
+
}
|
|
399
|
+
|
|
362
400
|
/** @param {string} content */
|
|
363
401
|
add_style(content) {
|
|
364
402
|
this.csp_provider.add_style(content);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { text } from '@sveltejs/kit';
|
|
2
|
-
import { Redirect } from '@sveltejs/kit/internal';
|
|
2
|
+
import { HttpError, Redirect } from '@sveltejs/kit/internal';
|
|
3
3
|
import { compact } from '../../../utils/array.js';
|
|
4
4
|
import { get_status, normalize_error } from '../../../utils/error.js';
|
|
5
5
|
import { add_data_suffix } from '../../pathname.js';
|
|
@@ -357,6 +357,11 @@ export async function render_page(
|
|
|
357
357
|
ssr === false ? server_data_serializer(event, event_state, options) : data_serializer
|
|
358
358
|
});
|
|
359
359
|
} catch (e) {
|
|
360
|
+
// a remote function could have thrown a redirect during render
|
|
361
|
+
if (e instanceof Redirect) {
|
|
362
|
+
return redirect_response(e.status, e.location);
|
|
363
|
+
}
|
|
364
|
+
|
|
360
365
|
// if we end up here, it means the data loaded successfully
|
|
361
366
|
// but the page failed to render, or that a prerendering error occurred
|
|
362
367
|
return await respond_with_error({
|
|
@@ -365,7 +370,7 @@ export async function render_page(
|
|
|
365
370
|
options,
|
|
366
371
|
manifest,
|
|
367
372
|
state,
|
|
368
|
-
status: 500,
|
|
373
|
+
status: e instanceof HttpError ? e.status : 500,
|
|
369
374
|
error: e,
|
|
370
375
|
resolve_opts
|
|
371
376
|
});
|
|
@@ -80,17 +80,11 @@ export async function render_response({
|
|
|
80
80
|
*/
|
|
81
81
|
const link_headers = new Set();
|
|
82
82
|
|
|
83
|
-
/**
|
|
84
|
-
* `<link>` tags that are added to prerendered responses
|
|
85
|
-
* (note that stylesheets are always added, prerendered or not)
|
|
86
|
-
* @type {Set<string>}
|
|
87
|
-
*/
|
|
88
|
-
const link_tags = new Set();
|
|
89
|
-
|
|
90
83
|
/** @type {Map<string, string>} */
|
|
91
84
|
// TODO if we add a client entry point one day, we will need to include inline_styles with the entry, otherwise stylesheets will be linked even if they are below inlineStyleThreshold
|
|
92
85
|
const inline_styles = new Map();
|
|
93
86
|
|
|
87
|
+
/** @type {ReturnType<typeof options.root.render>} */
|
|
94
88
|
let rendered;
|
|
95
89
|
|
|
96
90
|
const form_value =
|
|
@@ -110,6 +104,10 @@ export async function render_response({
|
|
|
110
104
|
*/
|
|
111
105
|
let base_expression = s(paths.base);
|
|
112
106
|
|
|
107
|
+
const csp = new Csp(options.csp, {
|
|
108
|
+
prerender: !!state.prerendering
|
|
109
|
+
});
|
|
110
|
+
|
|
113
111
|
// if appropriate, use relative paths for greater portability
|
|
114
112
|
if (paths.relative) {
|
|
115
113
|
if (!state.prerendering?.fallback) {
|
|
@@ -177,7 +175,8 @@ export async function render_response({
|
|
|
177
175
|
page: props.page
|
|
178
176
|
}
|
|
179
177
|
]
|
|
180
|
-
])
|
|
178
|
+
]),
|
|
179
|
+
csp: csp.script_needs_nonce ? { nonce: csp.nonce } : { hash: csp.script_needs_hash }
|
|
181
180
|
};
|
|
182
181
|
|
|
183
182
|
const fetch = globalThis.fetch;
|
|
@@ -227,9 +226,15 @@ export async function render_response({
|
|
|
227
226
|
paths.reset();
|
|
228
227
|
}
|
|
229
228
|
|
|
230
|
-
const { head, html, css } =
|
|
229
|
+
const { head, html, css, hashes } = /** @type {ReturnType<typeof options.root.render>} */ (
|
|
230
|
+
options.async ? await rendered : rendered
|
|
231
|
+
);
|
|
232
|
+
|
|
233
|
+
if (hashes) {
|
|
234
|
+
csp.add_script_hashes(hashes.script);
|
|
235
|
+
}
|
|
231
236
|
|
|
232
|
-
return { head, html, css };
|
|
237
|
+
return { head, html, css, hashes };
|
|
233
238
|
});
|
|
234
239
|
} finally {
|
|
235
240
|
if (DEV) {
|
|
@@ -245,20 +250,23 @@ export async function render_response({
|
|
|
245
250
|
for (const url of node.fonts) fonts.add(url);
|
|
246
251
|
|
|
247
252
|
if (node.inline_styles && !client.inline) {
|
|
248
|
-
Object.entries(await node.inline_styles()).forEach(([
|
|
253
|
+
Object.entries(await node.inline_styles()).forEach(([filename, css]) => {
|
|
254
|
+
if (typeof css === 'string') {
|
|
255
|
+
inline_styles.set(filename, css);
|
|
256
|
+
return;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
inline_styles.set(filename, css(`${assets}/${paths.app_dir}/immutable/assets`, assets));
|
|
260
|
+
});
|
|
249
261
|
}
|
|
250
262
|
}
|
|
251
263
|
} else {
|
|
252
|
-
rendered = { head: '', html: '', css: { code: '', map: null } };
|
|
264
|
+
rendered = { head: '', html: '', css: { code: '', map: null }, hashes: { script: [] } };
|
|
253
265
|
}
|
|
254
266
|
|
|
255
|
-
|
|
267
|
+
const head = new Head(rendered.head, !!state.prerendering);
|
|
256
268
|
let body = rendered.html;
|
|
257
269
|
|
|
258
|
-
const csp = new Csp(options.csp, {
|
|
259
|
-
prerender: !!state.prerendering
|
|
260
|
-
});
|
|
261
|
-
|
|
262
270
|
/** @param {string} path */
|
|
263
271
|
const prefixed = (path) => {
|
|
264
272
|
if (path.startsWith('/')) {
|
|
@@ -276,12 +284,10 @@ export async function render_response({
|
|
|
276
284
|
: Array.from(inline_styles.values()).join('\n');
|
|
277
285
|
|
|
278
286
|
if (style) {
|
|
279
|
-
const attributes = DEV ? ['
|
|
280
|
-
if (csp.style_needs_nonce) attributes.push(`
|
|
281
|
-
|
|
287
|
+
const attributes = DEV ? ['data-sveltekit'] : [];
|
|
288
|
+
if (csp.style_needs_nonce) attributes.push(`nonce="${csp.nonce}"`);
|
|
282
289
|
csp.add_style(style);
|
|
283
|
-
|
|
284
|
-
head += `\n\t<style${attributes.join('')}>${style}</style>`;
|
|
290
|
+
head.add_style(style, attributes);
|
|
285
291
|
}
|
|
286
292
|
|
|
287
293
|
for (const dep of stylesheets) {
|
|
@@ -299,7 +305,7 @@ export async function render_response({
|
|
|
299
305
|
}
|
|
300
306
|
}
|
|
301
307
|
|
|
302
|
-
head
|
|
308
|
+
head.add_stylesheet(path, attributes);
|
|
303
309
|
}
|
|
304
310
|
|
|
305
311
|
for (const dep of fonts) {
|
|
@@ -308,7 +314,7 @@ export async function render_response({
|
|
|
308
314
|
if (resolve_opts.preload({ type: 'font', path })) {
|
|
309
315
|
const ext = dep.slice(dep.lastIndexOf('.') + 1);
|
|
310
316
|
|
|
311
|
-
|
|
317
|
+
head.add_link_tag(path, ['rel="preload"', 'as="font"', `type="font/${ext}"`, 'crossorigin']);
|
|
312
318
|
|
|
313
319
|
link_headers.add(
|
|
314
320
|
`<${encodeURI(path)}>; rel="preload"; as="font"; type="font/${ext}"; crossorigin; nopush`
|
|
@@ -344,19 +350,13 @@ export async function render_response({
|
|
|
344
350
|
link_headers.add(`<${encodeURI(path)}>; rel="modulepreload"; nopush`);
|
|
345
351
|
|
|
346
352
|
if (options.preload_strategy !== 'modulepreload') {
|
|
347
|
-
head
|
|
353
|
+
head.add_script_preload(path);
|
|
348
354
|
} else {
|
|
349
|
-
|
|
355
|
+
head.add_link_tag(path, ['rel="modulepreload"']);
|
|
350
356
|
}
|
|
351
357
|
}
|
|
352
358
|
}
|
|
353
359
|
|
|
354
|
-
if (state.prerendering && link_tags.size > 0) {
|
|
355
|
-
head += Array.from(link_tags)
|
|
356
|
-
.map((tag) => `\n\t\t${tag}`)
|
|
357
|
-
.join('');
|
|
358
|
-
}
|
|
359
|
-
|
|
360
360
|
// prerender a `/path/to/page/__route.js` module
|
|
361
361
|
if (manifest._.client.routes && state.prerendering && !state.prerendering.fallback) {
|
|
362
362
|
const pathname = add_resolution_suffix(event.url.pathname);
|
|
@@ -574,19 +574,15 @@ export async function render_response({
|
|
|
574
574
|
|
|
575
575
|
if (state.prerendering) {
|
|
576
576
|
// TODO read headers set with setHeaders and convert into http-equiv where possible
|
|
577
|
-
const http_equiv = [];
|
|
578
|
-
|
|
579
577
|
const csp_headers = csp.csp_provider.get_meta();
|
|
580
578
|
if (csp_headers) {
|
|
581
|
-
|
|
579
|
+
head.add_http_equiv(csp_headers);
|
|
582
580
|
}
|
|
583
581
|
|
|
584
582
|
if (state.prerendering.cache) {
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
if (http_equiv.length > 0) {
|
|
589
|
-
head = http_equiv.join('\n') + head;
|
|
583
|
+
head.add_http_equiv(
|
|
584
|
+
`<meta http-equiv="cache-control" content="${state.prerendering.cache}">`
|
|
585
|
+
);
|
|
590
586
|
}
|
|
591
587
|
} else {
|
|
592
588
|
const csp_header = csp.csp_provider.get_header();
|
|
@@ -603,11 +599,8 @@ export async function render_response({
|
|
|
603
599
|
}
|
|
604
600
|
}
|
|
605
601
|
|
|
606
|
-
// add the content after the script/css links so the link elements are parsed first
|
|
607
|
-
head += rendered.head;
|
|
608
|
-
|
|
609
602
|
const html = options.templates.app({
|
|
610
|
-
head,
|
|
603
|
+
head: head.build(),
|
|
611
604
|
body,
|
|
612
605
|
assets,
|
|
613
606
|
nonce: /** @type {string} */ (csp.nonce),
|
|
@@ -665,3 +658,78 @@ export async function render_response({
|
|
|
665
658
|
}
|
|
666
659
|
);
|
|
667
660
|
}
|
|
661
|
+
|
|
662
|
+
class Head {
|
|
663
|
+
#rendered;
|
|
664
|
+
#prerendering;
|
|
665
|
+
/** @type {string[]} */
|
|
666
|
+
#http_equiv = [];
|
|
667
|
+
/** @type {string[]} */
|
|
668
|
+
#link_tags = [];
|
|
669
|
+
/** @type {string[]} */
|
|
670
|
+
#script_preloads = [];
|
|
671
|
+
/** @type {string[]} */
|
|
672
|
+
#style_tags = [];
|
|
673
|
+
/** @type {string[]} */
|
|
674
|
+
#stylesheet_links = [];
|
|
675
|
+
|
|
676
|
+
/**
|
|
677
|
+
* @param {string} rendered
|
|
678
|
+
* @param {boolean} prerendering
|
|
679
|
+
*/
|
|
680
|
+
constructor(rendered, prerendering) {
|
|
681
|
+
this.#rendered = rendered;
|
|
682
|
+
this.#prerendering = prerendering;
|
|
683
|
+
}
|
|
684
|
+
|
|
685
|
+
build() {
|
|
686
|
+
return [
|
|
687
|
+
...this.#http_equiv,
|
|
688
|
+
...this.#link_tags,
|
|
689
|
+
...this.#script_preloads,
|
|
690
|
+
this.#rendered,
|
|
691
|
+
...this.#style_tags,
|
|
692
|
+
...this.#stylesheet_links
|
|
693
|
+
].join('\n\t\t');
|
|
694
|
+
}
|
|
695
|
+
|
|
696
|
+
/**
|
|
697
|
+
* @param {string} style
|
|
698
|
+
* @param {string[]} attributes
|
|
699
|
+
*/
|
|
700
|
+
add_style(style, attributes) {
|
|
701
|
+
this.#style_tags.push(
|
|
702
|
+
`<style${attributes.length ? ' ' + attributes.join(' ') : ''}>${style}</style>`
|
|
703
|
+
);
|
|
704
|
+
}
|
|
705
|
+
|
|
706
|
+
/**
|
|
707
|
+
* @param {string} href
|
|
708
|
+
* @param {string[]} attributes
|
|
709
|
+
*/
|
|
710
|
+
add_stylesheet(href, attributes) {
|
|
711
|
+
this.#stylesheet_links.push(`<link href="${href}" ${attributes.join(' ')}>`);
|
|
712
|
+
}
|
|
713
|
+
|
|
714
|
+
/** @param {string} href */
|
|
715
|
+
add_script_preload(href) {
|
|
716
|
+
this.#script_preloads.push(
|
|
717
|
+
`<link rel="preload" as="script" crossorigin="anonymous" href="${href}">`
|
|
718
|
+
);
|
|
719
|
+
}
|
|
720
|
+
|
|
721
|
+
/**
|
|
722
|
+
* @param {string} href
|
|
723
|
+
* @param {string[]} attributes
|
|
724
|
+
*/
|
|
725
|
+
add_link_tag(href, attributes) {
|
|
726
|
+
if (!this.#prerendering) return;
|
|
727
|
+
this.#link_tags.push(`<link href="${href}" ${attributes.join(' ')}>`);
|
|
728
|
+
}
|
|
729
|
+
|
|
730
|
+
/** @param {string} tag */
|
|
731
|
+
add_http_equiv(tag) {
|
|
732
|
+
if (!this.#prerendering) return;
|
|
733
|
+
this.#http_equiv.push(tag);
|
|
734
|
+
}
|
|
735
|
+
}
|
|
@@ -73,23 +73,12 @@ async function handle_remote_call_internal(event, state, options, manifest, id)
|
|
|
73
73
|
/** @type {{ payloads: string[] }} */
|
|
74
74
|
const { payloads } = await event.request.json();
|
|
75
75
|
|
|
76
|
-
const args =
|
|
77
|
-
|
|
78
|
-
const results = await Promise.all(
|
|
79
|
-
args.map(async (arg, i) => {
|
|
80
|
-
try {
|
|
81
|
-
return { type: 'result', data: get_result(arg, i) };
|
|
82
|
-
} catch (error) {
|
|
83
|
-
return {
|
|
84
|
-
type: 'error',
|
|
85
|
-
error: await handle_error_and_jsonify(event, state, options, error),
|
|
86
|
-
status:
|
|
87
|
-
error instanceof HttpError || error instanceof SvelteKitError ? error.status : 500
|
|
88
|
-
};
|
|
89
|
-
}
|
|
90
|
-
})
|
|
76
|
+
const args = await Promise.all(
|
|
77
|
+
payloads.map((payload) => parse_remote_arg(payload, transport))
|
|
91
78
|
);
|
|
92
79
|
|
|
80
|
+
const results = await with_request_store({ event, state }, () => info.run(args, options));
|
|
81
|
+
|
|
93
82
|
return json(
|
|
94
83
|
/** @type {RemoteFunctionResponse} */ ({
|
|
95
84
|
type: 'result',
|