@sveltejs/kit 3.0.0-next.2 → 3.0.0-next.21
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 +62 -36
- package/src/cli.js +15 -12
- package/src/constants.js +6 -1
- package/src/core/adapt/builder.js +66 -72
- package/src/core/adapt/index.js +17 -6
- package/src/core/config/index.js +134 -80
- package/src/core/config/options.js +295 -273
- package/src/core/config/types.d.ts +1 -1
- package/src/core/env.js +146 -16
- package/src/core/generate_manifest/index.js +18 -15
- package/src/core/postbuild/analyse.js +8 -20
- package/src/core/postbuild/crawl.js +22 -6
- package/src/core/postbuild/entities.js +8 -2
- package/src/core/postbuild/fallback.js +4 -2
- package/src/core/postbuild/prerender.js +222 -70
- package/src/core/postbuild/queue.js +2 -1
- package/src/core/sync/create_manifest_data/conflict.js +1 -1
- package/src/core/sync/create_manifest_data/index.js +82 -62
- package/src/core/sync/sync.js +40 -31
- package/src/core/sync/ts.js +1 -1
- package/src/core/sync/utils.js +22 -2
- package/src/core/sync/{write_non_ambient.js → write_app_types.js} +107 -58
- package/src/core/sync/write_client_manifest.js +14 -29
- package/src/core/sync/write_env.js +7 -5
- package/src/core/sync/write_server.js +37 -45
- package/src/core/sync/write_tsconfig/index.js +274 -0
- package/src/core/sync/write_tsconfig/test-app/package.json +7 -0
- package/src/core/sync/write_tsconfig/utils.js +77 -0
- package/src/core/sync/write_tsconfig/validate.js +128 -0
- package/src/core/sync/write_types/index.js +127 -123
- package/src/core/utils.js +30 -5
- package/src/exports/env/index.js +77 -0
- package/src/exports/env/public.d.ts +55 -0
- package/src/exports/hooks/index.js +3 -9
- package/src/exports/hooks/public.d.ts +195 -0
- package/src/exports/hooks/sequence.js +9 -6
- package/src/exports/index.js +52 -29
- package/src/exports/internal/client.js +5 -0
- package/src/exports/internal/env.js +8 -5
- package/src/exports/internal/index.js +1 -90
- package/src/exports/internal/{event.js → server/event.js} +2 -3
- package/src/exports/internal/server/index.js +37 -0
- package/src/exports/internal/server/telemetry.js +95 -0
- package/src/exports/internal/shared.js +90 -0
- package/src/exports/node/index.js +64 -22
- package/src/exports/params/index.js +70 -0
- package/src/exports/params/public.d.ts +63 -0
- package/src/exports/public.d.ts +50 -1733
- package/src/exports/remote/index.js +11 -0
- package/src/exports/remote/public.d.ts +519 -0
- package/src/exports/url.js +86 -0
- package/src/exports/vite/build/build_server.js +54 -65
- package/src/exports/vite/build/remote.js +24 -19
- package/src/exports/vite/build/utils.js +0 -8
- package/src/exports/vite/dev/index.js +218 -146
- package/src/exports/vite/index.js +1590 -858
- package/src/exports/vite/module_ids.js +2 -2
- package/src/exports/vite/preview/index.js +40 -32
- package/src/exports/vite/public.d.ts +588 -0
- package/src/exports/vite/utils.js +84 -46
- package/src/pathname.js +55 -0
- package/src/runner.js +15 -0
- package/src/runtime/app/env/internal.js +4 -4
- package/src/runtime/app/env/types.d.ts +1 -1
- package/src/runtime/app/environment/index.js +3 -3
- package/src/runtime/app/{forms.js → forms/index.js} +73 -42
- package/src/runtime/app/forms/public.d.ts +2 -0
- package/src/runtime/app/forms/types.d.ts +56 -0
- package/src/runtime/app/internal/transport.js +53 -0
- package/src/runtime/app/manifest/index.js +1 -0
- package/src/runtime/app/{navigation.js → navigation/index.js} +2 -1
- package/src/runtime/app/navigation/public.d.ts +237 -0
- package/src/runtime/app/paths/client.js +37 -37
- package/src/runtime/app/paths/index.js +1 -1
- package/src/runtime/app/paths/internal/client.js +34 -2
- package/src/runtime/app/paths/internal/server.js +6 -23
- package/src/runtime/app/paths/internal.d.ts +3 -0
- package/src/runtime/app/paths/public.d.ts +1 -29
- package/src/runtime/app/paths/server.js +36 -17
- package/src/runtime/app/paths/types.d.ts +11 -19
- package/src/runtime/app/server/index.js +2 -2
- package/src/runtime/app/server/public.d.ts +201 -0
- package/src/runtime/app/server/remote/command.js +13 -11
- package/src/runtime/app/server/remote/form.js +61 -39
- package/src/runtime/app/server/remote/prerender.js +45 -45
- package/src/runtime/app/server/remote/query.js +106 -108
- package/src/runtime/app/server/remote/requested.js +27 -19
- package/src/runtime/app/server/remote/shared.js +76 -76
- package/src/runtime/app/service-worker/index.js +24 -0
- package/src/runtime/app/state/client.js +4 -2
- package/src/runtime/app/state/index.js +7 -5
- package/src/runtime/app/state/public.d.ts +72 -0
- package/src/runtime/app/state/server.js +3 -0
- package/src/runtime/app/stores.js +15 -78
- package/src/runtime/client/bundle.js +1 -1
- package/src/runtime/client/client-entry.js +3 -0
- package/src/runtime/client/client.js +1336 -648
- package/src/runtime/client/constants.js +3 -6
- package/src/runtime/client/entry.js +24 -3
- package/src/runtime/client/fetcher.js +25 -25
- package/src/runtime/client/ndjson.js +1 -1
- package/src/runtime/client/parse.js +1 -1
- package/src/runtime/client/payload.js +17 -0
- package/src/runtime/client/remote-functions/cache.svelte.js +3 -1
- package/src/runtime/client/remote-functions/command.svelte.js +37 -61
- package/src/runtime/client/remote-functions/form.svelte.js +267 -178
- package/src/runtime/client/remote-functions/prerender.svelte.js +32 -11
- package/src/runtime/client/remote-functions/query/index.js +10 -17
- package/src/runtime/client/remote-functions/query/instance.svelte.js +64 -18
- package/src/runtime/client/remote-functions/query/proxy.js +5 -5
- package/src/runtime/client/remote-functions/query-batch.svelte.js +61 -70
- package/src/runtime/client/remote-functions/query-live/index.js +1 -1
- package/src/runtime/client/remote-functions/query-live/instance.svelte.js +63 -21
- package/src/runtime/client/remote-functions/query-live/iterator.js +15 -12
- package/src/runtime/client/remote-functions/query-live/proxy.js +2 -12
- package/src/runtime/client/remote-functions/shared.svelte.js +90 -65
- package/src/runtime/client/snapshots.js +147 -0
- package/src/runtime/client/state.svelte.js +94 -55
- package/src/runtime/client/stream.js +3 -2
- package/src/runtime/client/types.d.ts +13 -9
- package/src/runtime/client/utils.js +22 -110
- package/src/runtime/components/root.svelte +56 -0
- package/src/runtime/env/dynamic/private.js +7 -0
- package/src/runtime/env/dynamic/public.js +7 -0
- package/src/runtime/env/static/private.js +6 -0
- package/src/runtime/env/static/public.js +6 -0
- package/src/runtime/form-utils.js +172 -61
- package/src/runtime/pathname.js +20 -32
- package/src/runtime/props.svelte.js +72 -0
- package/src/runtime/server/constants.js +0 -3
- package/src/runtime/server/cookie.js +72 -55
- package/src/runtime/server/csrf.js +65 -0
- package/src/runtime/server/data/index.js +49 -53
- package/src/runtime/server/dev.js +22 -0
- package/src/runtime/server/endpoint.js +6 -7
- package/src/runtime/server/env_module.js +0 -5
- package/src/runtime/server/errors.js +160 -0
- package/src/runtime/server/fetch.js +32 -39
- package/src/runtime/server/index.js +90 -64
- package/src/runtime/server/internal.js +71 -0
- package/src/runtime/server/page/actions.js +85 -64
- package/src/runtime/server/page/crypto.js +2 -2
- package/src/runtime/server/page/csp.js +88 -104
- package/src/runtime/server/page/data_serializer.js +24 -25
- package/src/runtime/server/page/index.js +36 -53
- package/src/runtime/server/page/load_data.js +50 -57
- package/src/runtime/server/page/render.js +173 -239
- package/src/runtime/server/page/respond_with_error.js +17 -31
- package/src/runtime/server/page/serialize_data.js +2 -13
- package/src/runtime/server/page/server_routing.js +85 -26
- package/src/runtime/server/remote-functions.js +640 -0
- package/src/runtime/server/respond.js +190 -131
- package/src/runtime/server/sourcemaps.js +183 -0
- package/src/runtime/server/state.js +53 -0
- package/src/runtime/server/utils.js +13 -155
- package/src/runtime/shared.js +20 -40
- package/src/runtime/utils.js +3 -0
- package/src/types/ambient-private.d.ts +11 -1
- package/src/types/ambient.d.ts +87 -36
- package/src/types/global-private.d.ts +25 -25
- package/src/types/internal.d.ts +163 -157
- package/src/types/private.d.ts +41 -1
- package/src/utils/error.js +28 -4
- package/src/utils/escape.js +9 -25
- package/src/utils/features.js +1 -1
- package/src/utils/filesystem.js +1 -23
- package/src/utils/fork.js +7 -2
- package/src/utils/hash.js +21 -0
- package/src/utils/http.js +8 -7
- package/src/utils/import.js +9 -2
- package/src/utils/imports.js +83 -0
- package/src/utils/mime.js +9 -0
- package/src/utils/page_nodes.js +6 -7
- package/src/utils/params.js +67 -0
- package/src/utils/regex.js +9 -0
- package/src/utils/routing.js +145 -73
- package/src/utils/shared-iterator.js +5 -0
- package/src/utils/streaming.js +14 -4
- package/src/utils/url.js +33 -2
- package/src/version.js +1 -1
- package/types/index.d.ts +2616 -2433
- package/types/index.d.ts.map +120 -106
- package/src/core/sync/write_ambient.js +0 -18
- package/src/core/sync/write_root.js +0 -148
- package/src/core/sync/write_tsconfig.js +0 -250
- package/src/exports/internal/server.js +0 -22
- package/src/exports/node/polyfills.js +0 -30
- package/src/runtime/server/app.js +0 -9
- package/src/runtime/server/remote.js +0 -457
- package/src/runtime/shared-server.js +0 -7
- package/src/runtime/telemetry/otel.js +0 -21
- package/src/runtime/telemetry/record_span.js +0 -65
- package/src/types/synthetic/$lib.md +0 -5
- /package/src/exports/internal/{remote-functions.js → server/remote-functions.js} +0 -0
- /package/src/{runtime/telemetry/noop.js → telemetry.js} +0 -0
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { parseCookie, parseSetCookie, stringifySetCookie } from 'cookie';
|
|
2
2
|
import { DEV } from 'esm-env';
|
|
3
3
|
import { normalize_path, resolve } from '../../utils/url.js';
|
|
4
4
|
import { add_data_suffix } from '../pathname.js';
|
|
@@ -12,10 +12,11 @@ import { text_encoder } from '../utils.js';
|
|
|
12
12
|
const cookie_paths = {};
|
|
13
13
|
|
|
14
14
|
/**
|
|
15
|
-
* Cookies
|
|
16
|
-
*
|
|
15
|
+
* Cookies whose name and value combined are larger than this size are
|
|
16
|
+
* discarded by browsers. This is the limit codified for the name/value pair
|
|
17
|
+
* in RFC 6265bis: https://datatracker.ietf.org/doc/html/draft-ietf-httpbis-rfc6265bis-20#section-5.6-7.5.1
|
|
17
18
|
*/
|
|
18
|
-
const MAX_COOKIE_SIZE =
|
|
19
|
+
const MAX_COOKIE_SIZE = 4096;
|
|
19
20
|
|
|
20
21
|
/**
|
|
21
22
|
* Generates a unique key for a cookie based on its domain, path, and name in
|
|
@@ -39,52 +40,68 @@ function generate_cookie_key(domain, path, name) {
|
|
|
39
40
|
export function get_cookies(request, url) {
|
|
40
41
|
const header = request.headers.get('cookie') ?? '';
|
|
41
42
|
const initial_cookies = /** @type {Record<string, string>} */ (
|
|
42
|
-
|
|
43
|
+
parseCookie(header, { decode: (value) => value })
|
|
43
44
|
);
|
|
44
45
|
|
|
46
|
+
/** @type {ReturnType<typeof parseCookie> | undefined} */
|
|
47
|
+
let default_cookies;
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* The header never changes during the request, so the default-decode parse is cached
|
|
51
|
+
* @param {import('cookie').ParseOptions} [opts]
|
|
52
|
+
*/
|
|
53
|
+
function parse_header(opts) {
|
|
54
|
+
return opts?.decode ? parseCookie(header, opts) : (default_cookies ??= parseCookie(header));
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/** @param {import('./page/types.js').Cookie} cookie */
|
|
58
|
+
function matches_url(cookie) {
|
|
59
|
+
return (
|
|
60
|
+
domain_matches(url.hostname, cookie.options.domain) &&
|
|
61
|
+
path_matches(url.pathname, cookie.options.path)
|
|
62
|
+
);
|
|
63
|
+
}
|
|
64
|
+
|
|
45
65
|
/** @type {string | undefined} */
|
|
46
66
|
let normalized_url;
|
|
47
67
|
|
|
48
68
|
/** @type {Map<string, import('./page/types.js').Cookie>} */
|
|
49
69
|
const new_cookies = new Map();
|
|
50
70
|
|
|
51
|
-
/** @type {import('cookie').
|
|
71
|
+
/** @type {Omit<import('cookie').SetCookie, 'name' | 'value'>} */
|
|
52
72
|
const defaults = {
|
|
53
73
|
httpOnly: true,
|
|
54
74
|
path: '/',
|
|
55
75
|
sameSite: 'lax',
|
|
56
|
-
secure: url.hostname === 'localhost' && url.protocol === 'http:'
|
|
76
|
+
secure: !__SVELTEKIT_DEV__ && !(url.hostname === 'localhost' && url.protocol === 'http:')
|
|
57
77
|
};
|
|
58
78
|
|
|
59
|
-
/** @type {import('
|
|
79
|
+
/** @type {import('$app/server').Cookies} */
|
|
60
80
|
const cookies = {
|
|
61
81
|
// The JSDoc param annotations appearing below for get, set and delete
|
|
62
82
|
// are necessary to expose the `cookie` library types to
|
|
63
|
-
// typescript users. `@type {import('
|
|
83
|
+
// typescript users. `@type {import('$app/server').Cookies}` above is not
|
|
64
84
|
// sufficient to do so.
|
|
65
85
|
|
|
66
|
-
/**
|
|
67
|
-
* @param {string} name
|
|
68
|
-
* @param {import('cookie').ParseOptions} [opts]
|
|
69
|
-
*/
|
|
70
86
|
get(name, opts) {
|
|
71
87
|
// Look for the most specific matching cookie from new_cookies
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
)
|
|
79
|
-
|
|
80
|
-
|
|
88
|
+
/** @type {import('./page/types.js').Cookie | undefined} */
|
|
89
|
+
let best_match;
|
|
90
|
+
for (const c of new_cookies.values()) {
|
|
91
|
+
if (
|
|
92
|
+
c.name === name &&
|
|
93
|
+
matches_url(c) &&
|
|
94
|
+
(!best_match || c.options.path.length > best_match.options.path.length)
|
|
95
|
+
) {
|
|
96
|
+
best_match = c;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
81
99
|
|
|
82
100
|
if (best_match) {
|
|
83
101
|
return best_match.options.maxAge === 0 ? undefined : best_match.value;
|
|
84
102
|
}
|
|
85
103
|
|
|
86
|
-
const
|
|
87
|
-
const cookie = req_cookies[name]; // the decoded string or undefined
|
|
104
|
+
const cookie = parse_header(opts)[name]; // the decoded string or undefined
|
|
88
105
|
|
|
89
106
|
// in development, if the cookie was set during this session with `cookies.set`,
|
|
90
107
|
// but at a different path, warn the user. (ignore cookies from request headers,
|
|
@@ -106,20 +123,15 @@ export function get_cookies(request, url) {
|
|
|
106
123
|
return cookie;
|
|
107
124
|
},
|
|
108
125
|
|
|
109
|
-
/**
|
|
110
|
-
* @param {import('cookie').ParseOptions} [opts]
|
|
111
|
-
*/
|
|
112
126
|
getAll(opts) {
|
|
113
|
-
|
|
127
|
+
// copy, so the cached parse isn't mutated below
|
|
128
|
+
const cookies = { ...parse_header(opts) };
|
|
114
129
|
|
|
115
130
|
// Group cookies by name and find the most specific one for each name
|
|
116
131
|
const lookup = new Map();
|
|
117
132
|
|
|
118
133
|
for (const c of new_cookies.values()) {
|
|
119
|
-
if (
|
|
120
|
-
domain_matches(url.hostname, c.options.domain) &&
|
|
121
|
-
path_matches(url.pathname, c.options.path)
|
|
122
|
-
) {
|
|
134
|
+
if (matches_url(c)) {
|
|
123
135
|
const existing = lookup.get(c.name);
|
|
124
136
|
|
|
125
137
|
// If no existing cookie or this one has a more specific (longer) path, use this one
|
|
@@ -131,7 +143,13 @@ export function get_cookies(request, url) {
|
|
|
131
143
|
|
|
132
144
|
// Add the most specific cookies to the result
|
|
133
145
|
for (const c of lookup.values()) {
|
|
134
|
-
cookies
|
|
146
|
+
// tombstones (deleted cookies) shadow request-header cookies,
|
|
147
|
+
// mirroring the behavior of `get()`
|
|
148
|
+
if (c.options.maxAge === 0) {
|
|
149
|
+
delete cookies[c.name];
|
|
150
|
+
} else {
|
|
151
|
+
cookies[c.name] = c.value;
|
|
152
|
+
}
|
|
135
153
|
}
|
|
136
154
|
|
|
137
155
|
return /** @type {Array<{ name: string; value: string }>} */ (
|
|
@@ -141,29 +159,17 @@ export function get_cookies(request, url) {
|
|
|
141
159
|
);
|
|
142
160
|
},
|
|
143
161
|
|
|
144
|
-
/**
|
|
145
|
-
* @param {string} name
|
|
146
|
-
* @param {string} value
|
|
147
|
-
* @param {import('cookie').SerializeOptions} options
|
|
148
|
-
*/
|
|
149
162
|
set(name, value, options) {
|
|
150
163
|
set_internal(name, value, { ...defaults, ...options });
|
|
151
164
|
},
|
|
152
165
|
|
|
153
|
-
/**
|
|
154
|
-
* @param {string} name
|
|
155
|
-
* @param {import('cookie').SerializeOptions} options
|
|
156
|
-
*/
|
|
157
166
|
delete(name, options) {
|
|
158
167
|
cookies.set(name, '', { ...options, maxAge: 0 });
|
|
159
168
|
},
|
|
160
169
|
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
* @param {import('cookie').SerializeOptions} options
|
|
165
|
-
*/
|
|
166
|
-
serialize(name, value, options) {
|
|
170
|
+
parse: parseSetCookie,
|
|
171
|
+
|
|
172
|
+
serialize(name, value, { encode, ...options }) {
|
|
167
173
|
let path = options.path ?? '/';
|
|
168
174
|
|
|
169
175
|
if (!options.domain || options.domain === url.hostname) {
|
|
@@ -173,7 +179,7 @@ export function get_cookies(request, url) {
|
|
|
173
179
|
path = resolve(normalized_url, path);
|
|
174
180
|
}
|
|
175
181
|
|
|
176
|
-
return
|
|
182
|
+
return stringifySetCookie({ name, value, ...defaults, ...options, path }, { encode });
|
|
177
183
|
}
|
|
178
184
|
};
|
|
179
185
|
|
|
@@ -200,7 +206,7 @@ export function get_cookies(request, url) {
|
|
|
200
206
|
// explicit header has highest precedence
|
|
201
207
|
if (header) {
|
|
202
208
|
const parsed = /** @type {Record<string, string>} */ (
|
|
203
|
-
|
|
209
|
+
parseCookie(header, { decode: (value) => value })
|
|
204
210
|
);
|
|
205
211
|
for (const name in parsed) {
|
|
206
212
|
combined_cookies[name] = parsed[name];
|
|
@@ -238,8 +244,12 @@ export function get_cookies(request, url) {
|
|
|
238
244
|
new_cookies.set(cookie_key, cookie);
|
|
239
245
|
|
|
240
246
|
if (DEV) {
|
|
241
|
-
const
|
|
242
|
-
|
|
247
|
+
const size =
|
|
248
|
+
// only the name/value pair counts towards MAX_COOKIE_SIZE, not the other attributes
|
|
249
|
+
text_encoder.encode(name).byteLength +
|
|
250
|
+
text_encoder.encode((options.encode ?? encodeURIComponent)(value)).byteLength;
|
|
251
|
+
|
|
252
|
+
if (size > MAX_COOKIE_SIZE) {
|
|
243
253
|
throw new Error(`Cookie "${name}" is too large, and will be discarded by the browser`);
|
|
244
254
|
}
|
|
245
255
|
|
|
@@ -296,15 +306,22 @@ export function path_matches(path, constraint) {
|
|
|
296
306
|
*/
|
|
297
307
|
export function add_cookies_to_headers(headers, cookies) {
|
|
298
308
|
for (const new_cookie of cookies) {
|
|
299
|
-
const {
|
|
300
|
-
|
|
309
|
+
const {
|
|
310
|
+
name,
|
|
311
|
+
value,
|
|
312
|
+
options: { encode, ...options }
|
|
313
|
+
} = new_cookie;
|
|
314
|
+
headers.append('set-cookie', stringifySetCookie({ name, value, ...options }, { encode }));
|
|
301
315
|
|
|
302
316
|
// special case — for routes ending with .html, the route data lives in a sibling
|
|
303
317
|
// `.html__data.json` file rather than a child `/__data.json` file, which means
|
|
304
318
|
// we need to duplicate the cookie
|
|
305
319
|
if (options.path.endsWith('.html')) {
|
|
306
320
|
const path = add_data_suffix(options.path);
|
|
307
|
-
headers.append(
|
|
321
|
+
headers.append(
|
|
322
|
+
'set-cookie',
|
|
323
|
+
stringifySetCookie({ name, value, ...options, path }, { encode })
|
|
324
|
+
);
|
|
308
325
|
}
|
|
309
326
|
}
|
|
310
327
|
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { is_form_content_type } from '../../utils/http.js';
|
|
2
|
+
|
|
3
|
+
const mutating_form_methods = new Set(['POST', 'PUT', 'PATCH', 'DELETE']);
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* The origin SvelteKit treats as "self" when validating the `Origin` header on
|
|
7
|
+
* cross-site requests.
|
|
8
|
+
*
|
|
9
|
+
* By default (`paths.origin` is `undefined`), SvelteKit derives the origin
|
|
10
|
+
* from `request.url` (which is set by the adapter, and ultimately by the
|
|
11
|
+
* platform). When `paths.origin` is configured — for example so that a preview
|
|
12
|
+
* deployment whose URL isn't known at build time, or an app behind a reverse
|
|
13
|
+
* proxy, can declare a canonical origin — that value takes precedence.
|
|
14
|
+
*
|
|
15
|
+
* @param {string | undefined} paths_origin the configured `kit.paths.origin`
|
|
16
|
+
* @param {string} url_origin the origin derived from `request.url`
|
|
17
|
+
* @returns {string}
|
|
18
|
+
*/
|
|
19
|
+
export function get_self_origin(paths_origin, url_origin) {
|
|
20
|
+
return paths_origin || url_origin;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Determines whether a non-remote request should be rejected as a cross-site
|
|
25
|
+
* request forgery (CSRF). Used by `respond.js` to gate form `POST`/`PUT`/
|
|
26
|
+
* `PATCH`/`DELETE` requests whose `Origin` header doesn't match the app's
|
|
27
|
+
* self-origin (and isn't in `trusted_origins`).
|
|
28
|
+
*
|
|
29
|
+
* @param {{
|
|
30
|
+
* request: Request;
|
|
31
|
+
* request_origin: string | null;
|
|
32
|
+
* self_origin: string;
|
|
33
|
+
* trusted_origins: string[];
|
|
34
|
+
* }} input
|
|
35
|
+
* @returns {boolean}
|
|
36
|
+
*/
|
|
37
|
+
export function is_csrf_forbidden({ request, request_origin, self_origin, trusted_origins }) {
|
|
38
|
+
return (
|
|
39
|
+
(!request.headers.get('content-type') || is_form_content_type(request)) &&
|
|
40
|
+
mutating_form_methods.has(request.method) &&
|
|
41
|
+
request_origin !== self_origin &&
|
|
42
|
+
(!request_origin || !trusted_origins.includes(request_origin))
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Determines whether a remote-function request should be rejected as cross-site.
|
|
48
|
+
*
|
|
49
|
+
* Unlike form submissions, remote functions accept any content type (e.g.
|
|
50
|
+
* `application/json`), so the check is solely on the request method and origin:
|
|
51
|
+
* a non-`GET` request is forbidden when its `Origin` header doesn't match the
|
|
52
|
+
* app's self-origin. Unlike `is_csrf_forbidden`, entries in `trusted_origins`
|
|
53
|
+
* are *not* honoured — remote function endpoints are an implementation detail,
|
|
54
|
+
* not a public API, so cross-origin calls are forbidden regardless.
|
|
55
|
+
*
|
|
56
|
+
* @param {{
|
|
57
|
+
* request: Request;
|
|
58
|
+
* request_origin: string | null;
|
|
59
|
+
* self_origin: string;
|
|
60
|
+
* }} input
|
|
61
|
+
* @returns {boolean}
|
|
62
|
+
*/
|
|
63
|
+
export function is_remote_forbidden({ request, request_origin, self_origin }) {
|
|
64
|
+
return request.method !== 'GET' && request_origin !== self_origin;
|
|
65
|
+
}
|
|
@@ -1,39 +1,36 @@
|
|
|
1
1
|
import { text } from '@sveltejs/kit';
|
|
2
|
-
import {
|
|
2
|
+
import { Redirect } from '@sveltejs/kit/internal';
|
|
3
3
|
import { normalize_error } from '../../../utils/error.js';
|
|
4
4
|
import { once } from '../../../utils/functions.js';
|
|
5
5
|
import { server_data_serializer_json } from '../page/data_serializer.js';
|
|
6
6
|
import { load_server_data } from '../page/load_data.js';
|
|
7
|
-
import { handle_error_and_jsonify } from '../
|
|
7
|
+
import { handle_error_and_jsonify } from '../errors.js';
|
|
8
8
|
import { normalize_path } from '../../../utils/url.js';
|
|
9
9
|
import { text_encoder } from '../../utils.js';
|
|
10
|
+
import { with_version_header } from '../utils.js';
|
|
10
11
|
|
|
11
12
|
/**
|
|
12
|
-
* @param {import('
|
|
13
|
-
* @param {import('types').RequestState}
|
|
13
|
+
* @param {import('$app/server').RequestEvent} event
|
|
14
|
+
* @param {import('types').RequestState} state
|
|
14
15
|
* @param {import('types').SSRRoute} route
|
|
15
16
|
* @param {import('types').SSROptions} options
|
|
16
17
|
* @param {import('@sveltejs/kit').SSRManifest} manifest
|
|
17
|
-
* @param {import('types').SSRState} state
|
|
18
18
|
* @param {boolean[] | undefined} invalidated_data_nodes
|
|
19
19
|
* @param {import('types').TrailingSlash} trailing_slash
|
|
20
20
|
* @returns {Promise<Response>}
|
|
21
21
|
*/
|
|
22
22
|
export async function render_data(
|
|
23
23
|
event,
|
|
24
|
-
|
|
24
|
+
state,
|
|
25
25
|
route,
|
|
26
26
|
options,
|
|
27
27
|
manifest,
|
|
28
|
-
state,
|
|
29
28
|
invalidated_data_nodes,
|
|
30
29
|
trailing_slash
|
|
31
30
|
) {
|
|
32
31
|
if (!route.page) {
|
|
33
32
|
// requesting /__data.json should fail for a +server.js
|
|
34
|
-
return new Response(undefined, {
|
|
35
|
-
status: 404
|
|
36
|
-
});
|
|
33
|
+
return with_version_header(new Response(undefined, { status: 404 }));
|
|
37
34
|
}
|
|
38
35
|
|
|
39
36
|
try {
|
|
@@ -61,7 +58,6 @@ export async function render_data(
|
|
|
61
58
|
// load this. for the child, return as is. for the final result, stream things
|
|
62
59
|
return load_server_data({
|
|
63
60
|
event: new_event,
|
|
64
|
-
event_state,
|
|
65
61
|
state,
|
|
66
62
|
node,
|
|
67
63
|
parent: async () => {
|
|
@@ -96,31 +92,25 @@ export async function render_data(
|
|
|
96
92
|
return fn();
|
|
97
93
|
});
|
|
98
94
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
promises.map((p, i) =>
|
|
102
|
-
p.catch(async (error) => {
|
|
95
|
+
const data_serializer = server_data_serializer_json(event, state, options);
|
|
96
|
+
await Promise.all(
|
|
97
|
+
promises.map(async (p, i) => {
|
|
98
|
+
const node = await p.catch(async (error) => {
|
|
103
99
|
if (error instanceof Redirect) {
|
|
104
100
|
throw error;
|
|
105
101
|
}
|
|
106
102
|
|
|
107
|
-
|
|
108
|
-
length = Math.min(length, i + 1);
|
|
103
|
+
const transformed = await handle_error_and_jsonify(event, state, options, error);
|
|
109
104
|
|
|
110
105
|
return /** @type {import('types').ServerErrorNode} */ ({
|
|
111
106
|
type: 'error',
|
|
112
|
-
error:
|
|
113
|
-
status:
|
|
114
|
-
error instanceof HttpError || error instanceof SvelteKitError
|
|
115
|
-
? error.status
|
|
116
|
-
: undefined
|
|
107
|
+
error: transformed
|
|
117
108
|
});
|
|
118
|
-
})
|
|
119
|
-
)
|
|
120
|
-
);
|
|
109
|
+
});
|
|
121
110
|
|
|
122
|
-
|
|
123
|
-
|
|
111
|
+
data_serializer.add_node(i, node);
|
|
112
|
+
})
|
|
113
|
+
);
|
|
124
114
|
const { data, chunks } = data_serializer.get_data();
|
|
125
115
|
|
|
126
116
|
if (!chunks) {
|
|
@@ -129,26 +119,28 @@ export async function render_data(
|
|
|
129
119
|
return json_response(data);
|
|
130
120
|
}
|
|
131
121
|
|
|
132
|
-
return
|
|
133
|
-
new
|
|
134
|
-
|
|
135
|
-
controller
|
|
136
|
-
|
|
137
|
-
|
|
122
|
+
return with_version_header(
|
|
123
|
+
new Response(
|
|
124
|
+
new ReadableStream({
|
|
125
|
+
async start(controller) {
|
|
126
|
+
controller.enqueue(text_encoder.encode(data));
|
|
127
|
+
for await (const chunk of chunks) {
|
|
128
|
+
controller.enqueue(text_encoder.encode(chunk));
|
|
129
|
+
}
|
|
130
|
+
controller.close();
|
|
131
|
+
},
|
|
132
|
+
|
|
133
|
+
type: 'bytes'
|
|
134
|
+
}),
|
|
135
|
+
{
|
|
136
|
+
headers: {
|
|
137
|
+
// we use a proprietary content type to prevent buffering.
|
|
138
|
+
// the `text` prefix makes it inspectable
|
|
139
|
+
'content-type': 'text/sveltekit-data',
|
|
140
|
+
'cache-control': 'private, no-store'
|
|
138
141
|
}
|
|
139
|
-
controller.close();
|
|
140
|
-
},
|
|
141
|
-
|
|
142
|
-
type: 'bytes'
|
|
143
|
-
}),
|
|
144
|
-
{
|
|
145
|
-
headers: {
|
|
146
|
-
// we use a proprietary content type to prevent buffering.
|
|
147
|
-
// the `text` prefix makes it inspectable
|
|
148
|
-
'content-type': 'text/sveltekit-data',
|
|
149
|
-
'cache-control': 'private, no-store'
|
|
150
142
|
}
|
|
151
|
-
|
|
143
|
+
)
|
|
152
144
|
);
|
|
153
145
|
} catch (e) {
|
|
154
146
|
const error = normalize_error(e);
|
|
@@ -156,7 +148,8 @@ export async function render_data(
|
|
|
156
148
|
if (error instanceof Redirect) {
|
|
157
149
|
return redirect_json_response(error);
|
|
158
150
|
} else {
|
|
159
|
-
|
|
151
|
+
const transformed = await handle_error_and_jsonify(event, state, options, error);
|
|
152
|
+
return json_response(transformed, transformed.status);
|
|
160
153
|
}
|
|
161
154
|
}
|
|
162
155
|
}
|
|
@@ -166,13 +159,15 @@ export async function render_data(
|
|
|
166
159
|
* @param {number} [status]
|
|
167
160
|
*/
|
|
168
161
|
function json_response(json, status = 200) {
|
|
169
|
-
return
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
162
|
+
return with_version_header(
|
|
163
|
+
text(typeof json === 'string' ? json : JSON.stringify(json), {
|
|
164
|
+
status,
|
|
165
|
+
headers: {
|
|
166
|
+
'content-type': 'application/json',
|
|
167
|
+
'cache-control': 'private, no-store'
|
|
168
|
+
}
|
|
169
|
+
})
|
|
170
|
+
);
|
|
176
171
|
}
|
|
177
172
|
|
|
178
173
|
/**
|
|
@@ -182,6 +177,7 @@ export function redirect_json_response(redirect) {
|
|
|
182
177
|
return json_response(
|
|
183
178
|
/** @type {import('types').ServerRedirectNode} */ ({
|
|
184
179
|
type: 'redirect',
|
|
180
|
+
status: redirect.status,
|
|
185
181
|
location: redirect.location
|
|
186
182
|
})
|
|
187
183
|
);
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
const symbol = Symbol.for('sveltekit.global_state');
|
|
2
|
+
const state = /** @type {Record<symbol, any>} */ (
|
|
3
|
+
/** @type {Record<symbol, unknown>} */ (/** @type {unknown} */ (globalThis))[symbol] ??= {}
|
|
4
|
+
);
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Persist a value across dev server reloads, in case a freshly-invalidated module
|
|
8
|
+
* reads global state that is not set until a request is handled
|
|
9
|
+
* @param {symbol} key
|
|
10
|
+
* @param {any} value
|
|
11
|
+
*/
|
|
12
|
+
export function save(key, value) {
|
|
13
|
+
state[key] = value;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Restore a value after a dev server reload
|
|
18
|
+
* @param {symbol} key
|
|
19
|
+
*/
|
|
20
|
+
export function restore(key) {
|
|
21
|
+
return state[key];
|
|
22
|
+
}
|
|
@@ -5,13 +5,12 @@ import { negotiate } from '../../utils/http.js';
|
|
|
5
5
|
import { method_not_allowed } from './utils.js';
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
|
-
* @param {import('
|
|
9
|
-
* @param {import('types').RequestState}
|
|
8
|
+
* @param {import('$app/server').RequestEvent} event
|
|
9
|
+
* @param {import('types').RequestState} state
|
|
10
10
|
* @param {import('types').SSREndpoint} mod
|
|
11
|
-
* @param {import('types').SSRState} state
|
|
12
11
|
* @returns {Promise<Response>}
|
|
13
12
|
*/
|
|
14
|
-
export async function render_endpoint(event,
|
|
13
|
+
export async function render_endpoint(event, state, mod) {
|
|
15
14
|
const method = /** @type {import('types').HttpMethod} */ (event.request.method);
|
|
16
15
|
|
|
17
16
|
let handler = mod[method] || mod.fallback;
|
|
@@ -42,8 +41,8 @@ export async function render_endpoint(event, event_state, mod, state) {
|
|
|
42
41
|
}
|
|
43
42
|
|
|
44
43
|
try {
|
|
45
|
-
const response = await with_request_store({ event, state
|
|
46
|
-
handler(/** @type {import('
|
|
44
|
+
const response = await with_request_store({ event, state }, () =>
|
|
45
|
+
handler(/** @type {import('$app/server').RequestEvent<Record<string, any>>} */ (event))
|
|
47
46
|
);
|
|
48
47
|
|
|
49
48
|
if (!(response instanceof Response)) {
|
|
@@ -90,7 +89,7 @@ export async function render_endpoint(event, event_state, mod, state) {
|
|
|
90
89
|
}
|
|
91
90
|
|
|
92
91
|
/**
|
|
93
|
-
* @param {import('
|
|
92
|
+
* @param {import('$app/server').RequestEvent} event
|
|
94
93
|
*/
|
|
95
94
|
export function is_endpoint_request(event) {
|
|
96
95
|
const { method, headers } = event.request;
|
|
@@ -16,7 +16,6 @@ let headers;
|
|
|
16
16
|
*/
|
|
17
17
|
export function get_public_env(request) {
|
|
18
18
|
const env = rendered_env;
|
|
19
|
-
const script = request.url.endsWith('.script.js');
|
|
20
19
|
|
|
21
20
|
payload ??= devalue.uneval(env);
|
|
22
21
|
etag ??= `W/${Date.now()}`;
|
|
@@ -29,9 +28,5 @@ export function get_public_env(request) {
|
|
|
29
28
|
return new Response(undefined, { status: 304, headers });
|
|
30
29
|
}
|
|
31
30
|
|
|
32
|
-
if (script) {
|
|
33
|
-
return new Response(`globalThis.__sveltekit_sw={env:${payload}}`, { headers });
|
|
34
|
-
}
|
|
35
|
-
|
|
36
31
|
return new Response(`export const env=${payload}`, { headers });
|
|
37
32
|
}
|