@sveltejs/kit 1.0.0-next.511 → 1.0.0-next.513
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 +3 -3
- package/src/constants.js +1 -1
- package/src/core/adapt/builder.js +9 -5
- package/src/core/sync/sync.js +11 -3
- package/src/core/sync/write_types/index.js +1 -1
- package/src/runtime/app/forms.js +1 -0
- package/src/runtime/client/client.js +19 -19
- package/src/runtime/client/fetcher.js +1 -1
- package/src/runtime/server/data/index.js +3 -8
- package/src/runtime/server/index.js +3 -4
- package/src/runtime/server/page/actions.js +5 -4
- package/src/runtime/server/page/index.js +4 -4
- package/src/runtime/server/utils.js +3 -3
- package/src/utils/http.js +17 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sveltejs/kit",
|
|
3
|
-
"version": "1.0.0-next.
|
|
3
|
+
"version": "1.0.0-next.513",
|
|
4
4
|
"repository": {
|
|
5
5
|
"type": "git",
|
|
6
6
|
"url": "https://github.com/sveltejs/kit",
|
|
@@ -26,12 +26,12 @@
|
|
|
26
26
|
"devDependencies": {
|
|
27
27
|
"@playwright/test": "^1.25.0",
|
|
28
28
|
"@types/connect": "^3.4.35",
|
|
29
|
-
"@types/marked": "^4.0.
|
|
29
|
+
"@types/marked": "^4.0.7",
|
|
30
30
|
"@types/mime": "^3.0.0",
|
|
31
31
|
"@types/node": "^16.11.36",
|
|
32
32
|
"@types/sade": "^1.7.4",
|
|
33
33
|
"@types/set-cookie-parser": "^2.4.2",
|
|
34
|
-
"marked": "^4.
|
|
34
|
+
"marked": "^4.1.1",
|
|
35
35
|
"rollup": "^2.78.1",
|
|
36
36
|
"svelte": "^3.48.0",
|
|
37
37
|
"svelte-preprocess": "^4.10.6",
|
package/src/constants.js
CHANGED
|
@@ -5,6 +5,7 @@ import { pipeline } from 'stream';
|
|
|
5
5
|
import { promisify } from 'util';
|
|
6
6
|
import { copy, rimraf, mkdirp } from '../../utils/filesystem.js';
|
|
7
7
|
import { generate_manifest } from '../generate_manifest/index.js';
|
|
8
|
+
import { affects_path } from '../../utils/routing.js';
|
|
8
9
|
|
|
9
10
|
const pipe = promisify(pipeline);
|
|
10
11
|
|
|
@@ -46,11 +47,14 @@ export function create_builder({ config, build_data, routes, prerendered, log })
|
|
|
46
47
|
|
|
47
48
|
return {
|
|
48
49
|
id: route.id,
|
|
49
|
-
segments: route.id
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
50
|
+
segments: route.id
|
|
51
|
+
.split('/')
|
|
52
|
+
.filter(affects_path)
|
|
53
|
+
.map((segment) => ({
|
|
54
|
+
dynamic: segment.includes('['),
|
|
55
|
+
rest: segment.includes('[...'),
|
|
56
|
+
content: segment
|
|
57
|
+
})),
|
|
54
58
|
pattern: route.pattern,
|
|
55
59
|
methods: Array.from(methods)
|
|
56
60
|
};
|
package/src/core/sync/sync.js
CHANGED
|
@@ -18,9 +18,17 @@ export function init(config, mode) {
|
|
|
18
18
|
if (fs.existsSync('src/app.d.ts')) {
|
|
19
19
|
const content = fs.readFileSync('src/app.d.ts', 'utf-8');
|
|
20
20
|
if (content.includes('PageError')) {
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
21
|
+
if (content.includes('// interface PageError')) {
|
|
22
|
+
fs.writeFileSync(
|
|
23
|
+
'src/app.d.ts',
|
|
24
|
+
content.replace(/\/\/ interface PageError/g, '// interface Error')
|
|
25
|
+
);
|
|
26
|
+
console.warn('App.PageError has been renamed to App.Error — we updated your src/app.d.ts');
|
|
27
|
+
} else {
|
|
28
|
+
throw new Error(
|
|
29
|
+
'App.PageError has been renamed to App.Error — please update your src/app.d.ts'
|
|
30
|
+
);
|
|
31
|
+
}
|
|
24
32
|
}
|
|
25
33
|
}
|
|
26
34
|
|
package/src/runtime/app/forms.js
CHANGED
|
@@ -1,7 +1,13 @@
|
|
|
1
1
|
import { onMount, tick } from 'svelte';
|
|
2
2
|
import { make_trackable, decode_params, normalize_path } from '../../utils/url.js';
|
|
3
3
|
import { find_anchor, get_base_uri, scroll_state } from './utils.js';
|
|
4
|
-
import {
|
|
4
|
+
import {
|
|
5
|
+
lock_fetch,
|
|
6
|
+
unlock_fetch,
|
|
7
|
+
initial_fetch,
|
|
8
|
+
subsequent_fetch,
|
|
9
|
+
native_fetch
|
|
10
|
+
} from './fetcher.js';
|
|
5
11
|
import { parse } from './parse.js';
|
|
6
12
|
|
|
7
13
|
import Root from '__GENERATED__/root.svelte';
|
|
@@ -10,6 +16,7 @@ import { HttpError, Redirect } from '../control.js';
|
|
|
10
16
|
import { stores } from './singletons.js';
|
|
11
17
|
import { DATA_SUFFIX } from '../../constants.js';
|
|
12
18
|
import { unwrap_promises } from '../../utils/promises.js';
|
|
19
|
+
import * as devalue from 'devalue';
|
|
13
20
|
|
|
14
21
|
const SCROLL_KEY = 'sveltekit:scroll';
|
|
15
22
|
const INDEX_KEY = 'sveltekit:index';
|
|
@@ -1479,8 +1486,6 @@ export function create_client({ target, base, trailing_slash }) {
|
|
|
1479
1486
|
};
|
|
1480
1487
|
}
|
|
1481
1488
|
|
|
1482
|
-
let data_id = 1;
|
|
1483
|
-
|
|
1484
1489
|
/**
|
|
1485
1490
|
* @param {URL} url
|
|
1486
1491
|
* @param {boolean[]} invalid
|
|
@@ -1489,25 +1494,20 @@ let data_id = 1;
|
|
|
1489
1494
|
async function load_data(url, invalid) {
|
|
1490
1495
|
const data_url = new URL(url);
|
|
1491
1496
|
data_url.pathname = url.pathname.replace(/\/$/, '') + DATA_SUFFIX;
|
|
1492
|
-
data_url.searchParams.set('__invalid', invalid.map((x) => (x ? 'y' : 'n')).join(''));
|
|
1493
|
-
data_url.searchParams.set('__id', String(data_id++));
|
|
1494
|
-
|
|
1495
|
-
// The __data.js file is generated by the server and looks like
|
|
1496
|
-
// `window.__sveltekit_data = ${devalue.uneval(data)}`. We do this instead
|
|
1497
|
-
// of `export const data` because modules are cached indefinitely,
|
|
1498
|
-
// and that would cause memory leaks.
|
|
1499
|
-
//
|
|
1500
|
-
// The data is read and deleted in the same tick as the promise
|
|
1501
|
-
// resolves, so it's not vulnerable to race conditions
|
|
1502
|
-
await import(/* @vite-ignore */ data_url.href);
|
|
1503
1497
|
|
|
1504
|
-
|
|
1505
|
-
|
|
1498
|
+
const res = await native_fetch(data_url.href, {
|
|
1499
|
+
headers: {
|
|
1500
|
+
'x-sveltekit-invalidated': invalid.map((x) => (x ? '1' : '')).join(',')
|
|
1501
|
+
}
|
|
1502
|
+
});
|
|
1503
|
+
const server_data = await res.text();
|
|
1506
1504
|
|
|
1507
|
-
|
|
1508
|
-
|
|
1505
|
+
if (!res.ok) {
|
|
1506
|
+
// error message is a JSON-stringified string which devalue can't handle at the top level
|
|
1507
|
+
throw new Error(JSON.parse(server_data));
|
|
1508
|
+
}
|
|
1509
1509
|
|
|
1510
|
-
return server_data;
|
|
1510
|
+
return devalue.parse(server_data);
|
|
1511
1511
|
}
|
|
1512
1512
|
|
|
1513
1513
|
/**
|
|
@@ -15,7 +15,7 @@ import { DATA_SUFFIX } from '../../../constants.js';
|
|
|
15
15
|
*/
|
|
16
16
|
export async function render_data(event, route, options, state) {
|
|
17
17
|
if (!route.page) {
|
|
18
|
-
// requesting /__data.
|
|
18
|
+
// requesting /__data.json should fail for a +server.js
|
|
19
19
|
return new Response(undefined, {
|
|
20
20
|
status: 404
|
|
21
21
|
});
|
|
@@ -25,10 +25,8 @@ export async function render_data(event, route, options, state) {
|
|
|
25
25
|
const node_ids = [...route.page.layouts, route.page.leaf];
|
|
26
26
|
|
|
27
27
|
const invalidated =
|
|
28
|
-
event.
|
|
29
|
-
|
|
30
|
-
?.split('')
|
|
31
|
-
.map((x) => x === 'y') ?? node_ids.map(() => true);
|
|
28
|
+
event.request.headers.get('x-sveltekit-invalidated')?.split(',').map(Boolean) ??
|
|
29
|
+
node_ids.map(() => true);
|
|
32
30
|
|
|
33
31
|
let aborted = false;
|
|
34
32
|
|
|
@@ -38,9 +36,6 @@ export async function render_data(event, route, options, state) {
|
|
|
38
36
|
options.trailing_slash
|
|
39
37
|
);
|
|
40
38
|
|
|
41
|
-
url.searchParams.delete('__invalid');
|
|
42
|
-
url.searchParams.delete('__id');
|
|
43
|
-
|
|
44
39
|
const new_event = { ...event, url };
|
|
45
40
|
|
|
46
41
|
const functions = node_ids.map((n, i) => {
|
|
@@ -3,6 +3,7 @@ import { render_page } from './page/index.js';
|
|
|
3
3
|
import { render_response } from './page/render.js';
|
|
4
4
|
import { respond_with_error } from './page/respond_with_error.js';
|
|
5
5
|
import { coalesce_to_error } from '../../utils/error.js';
|
|
6
|
+
import { is_form_content_type } from '../../utils/http.js';
|
|
6
7
|
import { GENERIC_ERROR, handle_fatal_error } from './utils.js';
|
|
7
8
|
import { decode_params, disable_search, normalize_path } from '../../utils/url.js';
|
|
8
9
|
import { exec } from '../../utils/routing.js';
|
|
@@ -24,12 +25,10 @@ export async function respond(request, options, state) {
|
|
|
24
25
|
let url = new URL(request.url);
|
|
25
26
|
|
|
26
27
|
if (options.csrf.check_origin) {
|
|
27
|
-
const type = request.headers.get('content-type')?.split(';')[0];
|
|
28
|
-
|
|
29
28
|
const forbidden =
|
|
30
29
|
request.method === 'POST' &&
|
|
31
30
|
request.headers.get('origin') !== url.origin &&
|
|
32
|
-
(
|
|
31
|
+
is_form_content_type(request);
|
|
33
32
|
|
|
34
33
|
if (forbidden) {
|
|
35
34
|
return new Response(`Cross-site ${request.method} form submissions are forbidden`, {
|
|
@@ -292,7 +291,7 @@ export async function respond(request, options, state) {
|
|
|
292
291
|
// add headers/cookies here, rather than inside `resolve`, so that we
|
|
293
292
|
// can do it once for all responses instead of once per `return`
|
|
294
293
|
if (!is_data_request) {
|
|
295
|
-
// we only want to set cookies on __data.
|
|
294
|
+
// we only want to set cookies on __data.json requests, we don't
|
|
296
295
|
// want to cache stuff erroneously etc
|
|
297
296
|
for (const key in headers) {
|
|
298
297
|
const value = headers[key];
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { error, json } from '../../../exports/index.js';
|
|
2
2
|
import { normalize_error } from '../../../utils/error.js';
|
|
3
|
-
import { negotiate } from '../../../utils/http.js';
|
|
3
|
+
import { is_form_content_type, negotiate } from '../../../utils/http.js';
|
|
4
4
|
import { HttpError, Redirect, ValidationError } from '../../control.js';
|
|
5
5
|
import { handle_error_and_jsonify } from '../utils.js';
|
|
6
6
|
|
|
@@ -180,9 +180,10 @@ export async function call_action(event, actions) {
|
|
|
180
180
|
throw new Error(`No action with name '${name}' found`);
|
|
181
181
|
}
|
|
182
182
|
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
183
|
+
if (!is_form_content_type(event.request)) {
|
|
184
|
+
throw new Error(
|
|
185
|
+
`Actions expect form-encoded data (received ${event.request.headers.get('content-type')}`
|
|
186
|
+
);
|
|
186
187
|
}
|
|
187
188
|
|
|
188
189
|
return action(event);
|
|
@@ -205,10 +205,10 @@ export async function render_page(event, route, page, options, state, resolve_op
|
|
|
205
205
|
|
|
206
206
|
if (err instanceof Redirect) {
|
|
207
207
|
if (state.prerendering && should_prerender_data) {
|
|
208
|
-
const body =
|
|
208
|
+
const body = devalue.stringify({
|
|
209
209
|
type: 'redirect',
|
|
210
210
|
location: err.location
|
|
211
|
-
})
|
|
211
|
+
});
|
|
212
212
|
|
|
213
213
|
state.prerendering.dependencies.set(data_pathname, {
|
|
214
214
|
response: new Response(body),
|
|
@@ -260,10 +260,10 @@ export async function render_page(event, route, page, options, state, resolve_op
|
|
|
260
260
|
}
|
|
261
261
|
|
|
262
262
|
if (state.prerendering && should_prerender_data) {
|
|
263
|
-
const body =
|
|
263
|
+
const body = devalue.stringify({
|
|
264
264
|
type: 'data',
|
|
265
265
|
nodes: branch.map((branch_node) => branch_node?.server_data)
|
|
266
|
-
})
|
|
266
|
+
});
|
|
267
267
|
|
|
268
268
|
state.prerendering.dependencies.set(data_pathname, {
|
|
269
269
|
response: new Response(body),
|
|
@@ -70,17 +70,17 @@ export function allowed_methods(mod) {
|
|
|
70
70
|
/** @param {any} data */
|
|
71
71
|
export function data_response(data) {
|
|
72
72
|
const headers = {
|
|
73
|
-
'content-type': 'application/
|
|
73
|
+
'content-type': 'application/json',
|
|
74
74
|
'cache-control': 'private, no-store'
|
|
75
75
|
};
|
|
76
76
|
|
|
77
77
|
try {
|
|
78
|
-
return new Response(
|
|
78
|
+
return new Response(devalue.stringify(data), { headers });
|
|
79
79
|
} catch (e) {
|
|
80
80
|
const error = /** @type {any} */ (e);
|
|
81
81
|
const match = /\[(\d+)\]\.data\.(.+)/.exec(error.path);
|
|
82
82
|
const message = match ? `${error.message} (data.${match[2]})` : error.message;
|
|
83
|
-
return new Response(
|
|
83
|
+
return new Response(JSON.stringify(message), { headers, status: 500 });
|
|
84
84
|
}
|
|
85
85
|
}
|
|
86
86
|
|
package/src/utils/http.js
CHANGED
|
@@ -53,3 +53,20 @@ export function negotiate(accept, types) {
|
|
|
53
53
|
|
|
54
54
|
return accepted;
|
|
55
55
|
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Returns `true` if the request contains a `content-type` header with the given type
|
|
59
|
+
* @param {Request} request
|
|
60
|
+
* @param {...string} types
|
|
61
|
+
*/
|
|
62
|
+
export function is_content_type(request, ...types) {
|
|
63
|
+
const type = request.headers.get('content-type')?.split(';', 1)[0].trim() ?? '';
|
|
64
|
+
return types.includes(type);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* @param {Request} request
|
|
69
|
+
*/
|
|
70
|
+
export function is_form_content_type(request) {
|
|
71
|
+
return is_content_type(request, 'application/x-www-form-urlencoded', 'multipart/form-data');
|
|
72
|
+
}
|