@sveltejs/kit 2.50.2 → 2.52.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 +2 -2
- package/src/core/postbuild/analyse.js +2 -15
- package/src/core/sync/create_manifest_data/index.js +18 -1
- package/src/core/sync/sync.js +17 -0
- package/src/core/sync/write_non_ambient.js +38 -9
- 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 +5 -47
- package/src/exports/vite/dev/index.js +4 -21
- package/src/exports/vite/index.js +5 -8
- package/src/exports/vite/static_analysis/index.js +61 -42
- package/src/exports/vite/static_analysis/utils.js +17 -0
- package/src/runtime/app/paths/client.js +38 -0
- package/src/runtime/app/paths/public.d.ts +1 -1
- package/src/runtime/app/paths/server.js +42 -1
- package/src/runtime/client/client.js +36 -38
- package/src/runtime/server/fetch.js +6 -2
- package/src/runtime/server/page/csp.js +54 -22
- package/src/runtime/server/page/index.js +7 -2
- package/src/runtime/server/page/render.js +104 -43
- package/src/runtime/server/page/server_routing.js +4 -20
- package/src/runtime/server/respond.js +7 -13
- package/src/types/internal.d.ts +13 -4
- package/src/types/private.d.ts +1 -0
- package/src/utils/routing.js +25 -0
- package/src/version.js +1 -1
- package/types/index.d.ts +49 -2
- package/types/index.d.ts.map +7 -1
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
/** @import { ResolveArgs } from './types.js' */
|
|
3
3
|
import { base, assets, hash_routing } from './internal/client.js';
|
|
4
4
|
import { resolve_route } from '../../../utils/routing.js';
|
|
5
|
+
import { get_navigation_intent } from '../../client/client.js';
|
|
5
6
|
|
|
6
7
|
/**
|
|
7
8
|
* Resolve the URL of an asset in your `static` directory, by prefixing it with [`config.kit.paths.assets`](https://svelte.dev/docs/kit/configuration#paths) if configured, or otherwise by prefixing it with the base path.
|
|
@@ -58,4 +59,41 @@ export function resolve(...args) {
|
|
|
58
59
|
);
|
|
59
60
|
}
|
|
60
61
|
|
|
62
|
+
/**
|
|
63
|
+
* Match a path or URL to a route ID and extracts any parameters.
|
|
64
|
+
*
|
|
65
|
+
* @example
|
|
66
|
+
* ```js
|
|
67
|
+
* import { match } from '$app/paths';
|
|
68
|
+
*
|
|
69
|
+
* const route = await match('/blog/hello-world');
|
|
70
|
+
*
|
|
71
|
+
* if (route?.id === '/blog/[slug]') {
|
|
72
|
+
* const slug = route.params.slug;
|
|
73
|
+
* const response = await fetch(`/api/posts/${slug}`);
|
|
74
|
+
* const post = await response.json();
|
|
75
|
+
* }
|
|
76
|
+
* ```
|
|
77
|
+
* @since 2.52.0
|
|
78
|
+
*
|
|
79
|
+
* @param {Pathname | URL | (string & {})} url
|
|
80
|
+
* @returns {Promise<{ id: RouteId, params: Record<string, string> } | null>}
|
|
81
|
+
*/
|
|
82
|
+
export async function match(url) {
|
|
83
|
+
if (typeof url === 'string') {
|
|
84
|
+
url = new URL(url, location.href);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const intent = await get_navigation_intent(url, false);
|
|
88
|
+
|
|
89
|
+
if (intent) {
|
|
90
|
+
return {
|
|
91
|
+
id: /** @type {RouteId} */ (intent.route.id),
|
|
92
|
+
params: intent.params
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
return null;
|
|
97
|
+
}
|
|
98
|
+
|
|
61
99
|
export { base, assets, resolve as resolveRoute };
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { RouteId, Pathname, ResolvedPathname } from '$app/types';
|
|
2
2
|
import { ResolveArgs } from './types.js';
|
|
3
3
|
|
|
4
|
-
export { resolve, asset } from './client.js';
|
|
4
|
+
export { resolve, asset, match } from './client.js';
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* A string that matches [`config.kit.paths.base`](https://svelte.dev/docs/kit/configuration#paths).
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import { base, assets, relative, initial_base } from './internal/server.js';
|
|
2
|
-
import { resolve_route } from '../../../utils/routing.js';
|
|
2
|
+
import { resolve_route, find_route } from '../../../utils/routing.js';
|
|
3
|
+
import { decode_pathname } from '../../../utils/url.js';
|
|
3
4
|
import { try_get_request_store } from '@sveltejs/kit/internal/server';
|
|
5
|
+
import { manifest } from '__sveltekit/server';
|
|
6
|
+
import { get_hooks } from '__SERVER__/internal.js';
|
|
4
7
|
|
|
5
8
|
/** @type {import('./client.js').asset} */
|
|
6
9
|
export function asset(file) {
|
|
@@ -27,4 +30,42 @@ export function resolve(id, params) {
|
|
|
27
30
|
return base + resolved;
|
|
28
31
|
}
|
|
29
32
|
|
|
33
|
+
/** @type {import('./client.js').match} */
|
|
34
|
+
export async function match(url) {
|
|
35
|
+
const store = try_get_request_store();
|
|
36
|
+
|
|
37
|
+
if (typeof url === 'string') {
|
|
38
|
+
const origin = store?.event.url.origin ?? 'http://internal';
|
|
39
|
+
url = new URL(url, origin);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const { reroute } = await get_hooks();
|
|
43
|
+
|
|
44
|
+
let resolved_path = url.pathname;
|
|
45
|
+
|
|
46
|
+
try {
|
|
47
|
+
resolved_path = decode_pathname(
|
|
48
|
+
(await reroute?.({ url: new URL(url), fetch: store?.event.fetch ?? fetch })) ?? url.pathname
|
|
49
|
+
);
|
|
50
|
+
} catch {
|
|
51
|
+
return null;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
if (base && resolved_path.startsWith(base)) {
|
|
55
|
+
resolved_path = resolved_path.slice(base.length) || '/';
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const matchers = await manifest._.matchers();
|
|
59
|
+
const result = find_route(resolved_path, manifest._.routes, matchers);
|
|
60
|
+
|
|
61
|
+
if (result) {
|
|
62
|
+
return {
|
|
63
|
+
id: /** @type {import('$app/types').RouteId} */ (result.route.id),
|
|
64
|
+
params: result.params
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
return null;
|
|
69
|
+
}
|
|
70
|
+
|
|
30
71
|
export { base, assets, resolve as resolveRoute };
|
|
@@ -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',
|
|
@@ -1400,7 +1401,7 @@ async function get_rerouted_url(url) {
|
|
|
1400
1401
|
* @param {boolean} invalidating
|
|
1401
1402
|
* @returns {Promise<import('./types.js').NavigationIntent | undefined>}
|
|
1402
1403
|
*/
|
|
1403
|
-
async function get_navigation_intent(url, invalidating) {
|
|
1404
|
+
export async function get_navigation_intent(url, invalidating) {
|
|
1404
1405
|
if (!url) return;
|
|
1405
1406
|
if (is_external_url(url, base, app.hash)) return;
|
|
1406
1407
|
|
|
@@ -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
|
});
|
|
@@ -1758,26 +1761,18 @@ async function navigate({
|
|
|
1758
1761
|
await svelte.tick();
|
|
1759
1762
|
|
|
1760
1763
|
// we reset scroll before dealing with focus, to avoid a flash of unscrolled content
|
|
1761
|
-
|
|
1764
|
+
/** @type {Element | null | ''} */
|
|
1765
|
+
let deep_linked = null;
|
|
1762
1766
|
|
|
1763
1767
|
if (autoscroll) {
|
|
1764
|
-
const
|
|
1768
|
+
const scroll = popped ? popped.scroll : noscroll ? scroll_state() : null;
|
|
1765
1769
|
if (scroll) {
|
|
1766
1770
|
scrollTo(scroll.x, scroll.y);
|
|
1767
|
-
} else if (deep_linked) {
|
|
1771
|
+
} else if ((deep_linked = url.hash && document.getElementById(get_id(url)))) {
|
|
1768
1772
|
// Here we use `scrollIntoView` on the element instead of `scrollTo`
|
|
1769
1773
|
// because it natively supports the `scroll-margin` and `scroll-behavior`
|
|
1770
1774
|
// CSS properties.
|
|
1771
1775
|
deep_linked.scrollIntoView();
|
|
1772
|
-
|
|
1773
|
-
// Get target position at this point because with smooth scrolling the scroll position
|
|
1774
|
-
// retrieved from current x/y above might be wrong (since we might not have arrived at the destination yet)
|
|
1775
|
-
const { top, left } = deep_linked.getBoundingClientRect();
|
|
1776
|
-
|
|
1777
|
-
scroll = {
|
|
1778
|
-
x: pageXOffset + left,
|
|
1779
|
-
y: pageYOffset + top
|
|
1780
|
-
};
|
|
1781
1776
|
} else {
|
|
1782
1777
|
scrollTo(0, 0);
|
|
1783
1778
|
}
|
|
@@ -1791,7 +1786,10 @@ async function navigate({
|
|
|
1791
1786
|
document.activeElement !== document.body;
|
|
1792
1787
|
|
|
1793
1788
|
if (!keepfocus && !changed_focus) {
|
|
1794
|
-
|
|
1789
|
+
// We don't need to manually restore the scroll position if we're navigating
|
|
1790
|
+
// to a fragment identifier. It is automatically done for us when we set the
|
|
1791
|
+
// sequential navigation starting point with `location.replace`
|
|
1792
|
+
reset_focus(url, !deep_linked);
|
|
1795
1793
|
}
|
|
1796
1794
|
|
|
1797
1795
|
autoscroll = true;
|
|
@@ -1808,6 +1806,11 @@ async function navigate({
|
|
|
1808
1806
|
|
|
1809
1807
|
nav.fulfil(undefined);
|
|
1810
1808
|
|
|
1809
|
+
// Update to.scroll to the actual scroll position after navigation completed
|
|
1810
|
+
if (nav.navigation.to) {
|
|
1811
|
+
nav.navigation.to.scroll = scroll_state();
|
|
1812
|
+
}
|
|
1813
|
+
|
|
1811
1814
|
after_navigate_callbacks.forEach((fn) =>
|
|
1812
1815
|
fn(/** @type {import('@sveltejs/kit').AfterNavigate} */ (nav.navigation))
|
|
1813
1816
|
);
|
|
@@ -2991,9 +2994,9 @@ let resetting_focus = false;
|
|
|
2991
2994
|
|
|
2992
2995
|
/**
|
|
2993
2996
|
* @param {URL} url
|
|
2994
|
-
* @param {
|
|
2997
|
+
* @param {boolean} [scroll]
|
|
2995
2998
|
*/
|
|
2996
|
-
function reset_focus(url, scroll =
|
|
2999
|
+
function reset_focus(url, scroll = true) {
|
|
2997
3000
|
const autofocus = document.querySelector('[autofocus]');
|
|
2998
3001
|
if (autofocus) {
|
|
2999
3002
|
// @ts-ignore
|
|
@@ -3005,7 +3008,7 @@ function reset_focus(url, scroll = null) {
|
|
|
3005
3008
|
// starting point to the fragment identifier.
|
|
3006
3009
|
const id = get_id(url);
|
|
3007
3010
|
if (id && document.getElementById(id)) {
|
|
3008
|
-
const { x, y } =
|
|
3011
|
+
const { x, y } = scroll_state();
|
|
3009
3012
|
|
|
3010
3013
|
// `element.focus()` doesn't work on Safari and Firefox Ubuntu so we need
|
|
3011
3014
|
// to use this hack with `location.replace()` instead.
|
|
@@ -3013,24 +3016,16 @@ function reset_focus(url, scroll = null) {
|
|
|
3013
3016
|
const history_state = history.state;
|
|
3014
3017
|
|
|
3015
3018
|
resetting_focus = true;
|
|
3016
|
-
location.replace(`#${id}
|
|
3019
|
+
location.replace(new URL(`#${id}`, location.href));
|
|
3017
3020
|
|
|
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);
|
|
3021
|
+
// Firefox has a bug that sets the history state to `null` so we need to
|
|
3022
|
+
// restore it after. See https://bugzilla.mozilla.org/show_bug.cgi?id=1199924
|
|
3023
|
+
// This is also needed to restore the original hash if we're using hash routing
|
|
3024
|
+
history.replaceState(history_state, '', url);
|
|
3030
3025
|
|
|
3031
|
-
//
|
|
3026
|
+
// If scroll management has already happened earlier, we need to restore
|
|
3032
3027
|
// the scroll position after setting the sequential focus navigation starting point
|
|
3033
|
-
scrollTo(x, y);
|
|
3028
|
+
if (scroll) scrollTo(x, y);
|
|
3034
3029
|
resetting_focus = false;
|
|
3035
3030
|
});
|
|
3036
3031
|
} else {
|
|
@@ -3102,8 +3097,9 @@ function reset_focus(url, scroll = null) {
|
|
|
3102
3097
|
* @param {import('./types.js').NavigationIntent | undefined} intent
|
|
3103
3098
|
* @param {URL | null} url
|
|
3104
3099
|
* @param {T} type
|
|
3100
|
+
* @param {{ x: number, y: number } | null} [target_scroll] The scroll position for the target (for popstate navigations)
|
|
3105
3101
|
*/
|
|
3106
|
-
function create_navigation(current, intent, url, type) {
|
|
3102
|
+
function create_navigation(current, intent, url, type, target_scroll = null) {
|
|
3107
3103
|
/** @type {(value: any) => void} */
|
|
3108
3104
|
let fulfil;
|
|
3109
3105
|
|
|
@@ -3123,12 +3119,14 @@ function create_navigation(current, intent, url, type) {
|
|
|
3123
3119
|
from: {
|
|
3124
3120
|
params: current.params,
|
|
3125
3121
|
route: { id: current.route?.id ?? null },
|
|
3126
|
-
url: current.url
|
|
3122
|
+
url: current.url,
|
|
3123
|
+
scroll: scroll_state()
|
|
3127
3124
|
},
|
|
3128
3125
|
to: url && {
|
|
3129
3126
|
params: intent?.params ?? null,
|
|
3130
3127
|
route: { id: intent?.route?.id ?? null },
|
|
3131
|
-
url
|
|
3128
|
+
url,
|
|
3129
|
+
scroll: target_scroll
|
|
3132
3130
|
},
|
|
3133
3131
|
willUnload: !intent,
|
|
3134
3132
|
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'];
|
|
@@ -162,6 +171,7 @@ class BaseProvider {
|
|
|
162
171
|
|
|
163
172
|
this.script_needs_nonce = this.#script_needs_csp && !this.#use_hashes;
|
|
164
173
|
this.style_needs_nonce = this.#style_needs_csp && !this.#use_hashes;
|
|
174
|
+
this.script_needs_hash = this.#script_needs_csp && this.#use_hashes;
|
|
165
175
|
|
|
166
176
|
this.#nonce = nonce;
|
|
167
177
|
}
|
|
@@ -174,11 +184,23 @@ class BaseProvider {
|
|
|
174
184
|
const source = this.#use_hashes ? `sha256-${sha256(content)}` : `nonce-${this.#nonce}`;
|
|
175
185
|
|
|
176
186
|
if (this.#script_src_needs_csp) {
|
|
177
|
-
this.#script_src.
|
|
187
|
+
this.#script_src.add(source);
|
|
178
188
|
}
|
|
179
189
|
|
|
180
190
|
if (this.#script_src_elem_needs_csp) {
|
|
181
|
-
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
|
+
}
|
|
182
204
|
}
|
|
183
205
|
}
|
|
184
206
|
|
|
@@ -190,11 +212,11 @@ class BaseProvider {
|
|
|
190
212
|
const source = this.#use_hashes ? `sha256-${sha256(content)}` : `nonce-${this.#nonce}`;
|
|
191
213
|
|
|
192
214
|
if (this.#style_src_needs_csp) {
|
|
193
|
-
this.#style_src.
|
|
215
|
+
this.#style_src.add(source);
|
|
194
216
|
}
|
|
195
217
|
|
|
196
218
|
if (this.#style_src_attr_needs_csp) {
|
|
197
|
-
this.#style_src_attr.
|
|
219
|
+
this.#style_src_attr.add(source);
|
|
198
220
|
}
|
|
199
221
|
|
|
200
222
|
if (this.#style_src_elem_needs_csp) {
|
|
@@ -207,13 +229,13 @@ class BaseProvider {
|
|
|
207
229
|
if (
|
|
208
230
|
d['style-src-elem'] &&
|
|
209
231
|
!d['style-src-elem'].includes(sha256_empty_comment_hash) &&
|
|
210
|
-
!this.#style_src_elem.
|
|
232
|
+
!this.#style_src_elem.has(sha256_empty_comment_hash)
|
|
211
233
|
) {
|
|
212
|
-
this.#style_src_elem.
|
|
234
|
+
this.#style_src_elem.add(sha256_empty_comment_hash);
|
|
213
235
|
}
|
|
214
236
|
|
|
215
237
|
if (source !== sha256_empty_comment_hash) {
|
|
216
|
-
this.#style_src_elem.
|
|
238
|
+
this.#style_src_elem.add(source);
|
|
217
239
|
}
|
|
218
240
|
}
|
|
219
241
|
}
|
|
@@ -230,35 +252,35 @@ class BaseProvider {
|
|
|
230
252
|
|
|
231
253
|
const directives = { ...this.#directives };
|
|
232
254
|
|
|
233
|
-
if (this.#style_src.
|
|
255
|
+
if (this.#style_src.size > 0) {
|
|
234
256
|
directives['style-src'] = [
|
|
235
257
|
...(directives['style-src'] || directives['default-src'] || []),
|
|
236
258
|
...this.#style_src
|
|
237
259
|
];
|
|
238
260
|
}
|
|
239
261
|
|
|
240
|
-
if (this.#style_src_attr.
|
|
262
|
+
if (this.#style_src_attr.size > 0) {
|
|
241
263
|
directives['style-src-attr'] = [
|
|
242
264
|
...(directives['style-src-attr'] || []),
|
|
243
265
|
...this.#style_src_attr
|
|
244
266
|
];
|
|
245
267
|
}
|
|
246
268
|
|
|
247
|
-
if (this.#style_src_elem.
|
|
269
|
+
if (this.#style_src_elem.size > 0) {
|
|
248
270
|
directives['style-src-elem'] = [
|
|
249
271
|
...(directives['style-src-elem'] || []),
|
|
250
272
|
...this.#style_src_elem
|
|
251
273
|
];
|
|
252
274
|
}
|
|
253
275
|
|
|
254
|
-
if (this.#script_src.
|
|
276
|
+
if (this.#script_src.size > 0) {
|
|
255
277
|
directives['script-src'] = [
|
|
256
278
|
...(directives['script-src'] || directives['default-src'] || []),
|
|
257
279
|
...this.#script_src
|
|
258
280
|
];
|
|
259
281
|
}
|
|
260
282
|
|
|
261
|
-
if (this.#script_src_elem.
|
|
283
|
+
if (this.#script_src_elem.size > 0) {
|
|
262
284
|
directives['script-src-elem'] = [
|
|
263
285
|
...(directives['script-src-elem'] || []),
|
|
264
286
|
...this.#script_src_elem
|
|
@@ -351,6 +373,10 @@ export class Csp {
|
|
|
351
373
|
this.report_only_provider = new CspReportOnlyProvider(use_hashes, reportOnly, this.nonce);
|
|
352
374
|
}
|
|
353
375
|
|
|
376
|
+
get script_needs_hash() {
|
|
377
|
+
return this.csp_provider.script_needs_hash || this.report_only_provider.script_needs_hash;
|
|
378
|
+
}
|
|
379
|
+
|
|
354
380
|
get script_needs_nonce() {
|
|
355
381
|
return this.csp_provider.script_needs_nonce || this.report_only_provider.script_needs_nonce;
|
|
356
382
|
}
|
|
@@ -365,6 +391,12 @@ export class Csp {
|
|
|
365
391
|
this.report_only_provider.add_script(content);
|
|
366
392
|
}
|
|
367
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
|
+
|
|
368
400
|
/** @param {string} content */
|
|
369
401
|
add_style(content) {
|
|
370
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
|
});
|