@sveltejs/kit 1.0.0-next.533 → 1.0.0-next.534
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/sync/write_types/index.js +25 -6
- package/src/exports/vite/build/build_server.js +1 -1
- package/src/exports/vite/dev/index.js +1 -1
- package/src/runtime/client/client.js +106 -50
- package/src/runtime/client/types.d.ts +1 -1
- package/src/runtime/server/data/index.js +31 -15
- package/src/runtime/server/endpoint.js +1 -1
- package/src/runtime/server/index.js +5 -4
- package/src/runtime/server/page/actions.js +2 -2
- package/src/runtime/server/page/index.js +6 -6
- package/src/runtime/server/page/load_data.js +10 -8
- package/src/runtime/server/page/render.js +26 -25
- package/src/runtime/server/utils.js +44 -22
- package/types/ambient.d.ts +2 -2
- package/types/index.d.ts +51 -24
- package/types/internal.d.ts +2 -6
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.534",
|
|
4
4
|
"repository": {
|
|
5
5
|
"type": "git",
|
|
6
6
|
"url": "https://github.com/sveltejs/kit",
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
"@sveltejs/vite-plugin-svelte": "^1.1.0",
|
|
14
14
|
"@types/cookie": "^0.5.1",
|
|
15
15
|
"cookie": "^0.5.0",
|
|
16
|
-
"devalue": "^4.
|
|
16
|
+
"devalue": "^4.2.0",
|
|
17
17
|
"kleur": "^4.1.5",
|
|
18
18
|
"magic-string": "^0.26.7",
|
|
19
19
|
"mime": "^3.0.0",
|
|
@@ -200,6 +200,8 @@ function update_types(config, routes, route, to_delete = new Set()) {
|
|
|
200
200
|
.join('; ')} }`
|
|
201
201
|
);
|
|
202
202
|
|
|
203
|
+
declarations.push(`type RouteId = '${route.id}';`);
|
|
204
|
+
|
|
203
205
|
// These could also be placed in our public types, but it would bloat them unnecessarily and we may want to change these in the future
|
|
204
206
|
if (route.layout || route.leaf) {
|
|
205
207
|
// If T extends the empty object, void is also allowed as a return type
|
|
@@ -249,17 +251,25 @@ function update_types(config, routes, route, to_delete = new Set()) {
|
|
|
249
251
|
}
|
|
250
252
|
|
|
251
253
|
if (route.leaf.server) {
|
|
252
|
-
exports.push(
|
|
253
|
-
|
|
254
|
+
exports.push(
|
|
255
|
+
`export type Action<OutputData extends Record<string, any> | void = Record<string, any> | void> = Kit.Action<RouteParams, OutputData, RouteId>`
|
|
256
|
+
);
|
|
257
|
+
exports.push(
|
|
258
|
+
`export type Actions<OutputData extends Record<string, any> | void = Record<string, any> | void> = Kit.Actions<RouteParams, OutputData, RouteId>`
|
|
259
|
+
);
|
|
254
260
|
}
|
|
255
261
|
}
|
|
256
262
|
|
|
257
263
|
if (route.layout) {
|
|
258
264
|
let all_pages_have_load = true;
|
|
259
265
|
const layout_params = new Set();
|
|
266
|
+
const ids = ['RouteId'];
|
|
267
|
+
|
|
260
268
|
route.layout.child_pages?.forEach((page) => {
|
|
261
269
|
const leaf = routes.get(page);
|
|
262
270
|
if (leaf) {
|
|
271
|
+
if (leaf.route.page) ids.push(`"${leaf.route.id}"`);
|
|
272
|
+
|
|
263
273
|
for (const name of leaf.route.names) {
|
|
264
274
|
layout_params.add(name);
|
|
265
275
|
}
|
|
@@ -280,6 +290,13 @@ function update_types(config, routes, route, to_delete = new Set()) {
|
|
|
280
290
|
}
|
|
281
291
|
});
|
|
282
292
|
|
|
293
|
+
if (route.id === '/') {
|
|
294
|
+
// root layout is used for fallback error page, where ID can be null
|
|
295
|
+
ids.push('null');
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
declarations.push(`type LayoutRouteId = ${ids.join(' | ')}`);
|
|
299
|
+
|
|
283
300
|
declarations.push(
|
|
284
301
|
`type LayoutParams = RouteParams & { ${Array.from(layout_params).map(
|
|
285
302
|
(param) => `${param}?: string`
|
|
@@ -306,11 +323,11 @@ function update_types(config, routes, route, to_delete = new Set()) {
|
|
|
306
323
|
}
|
|
307
324
|
|
|
308
325
|
if (route.endpoint) {
|
|
309
|
-
exports.push(`export type RequestHandler = Kit.RequestHandler<RouteParams>;`);
|
|
326
|
+
exports.push(`export type RequestHandler = Kit.RequestHandler<RouteParams, RouteId>;`);
|
|
310
327
|
}
|
|
311
328
|
|
|
312
329
|
if (route.leaf?.server || route.layout?.server || route.endpoint) {
|
|
313
|
-
exports.push(`export type RequestEvent = Kit.RequestEvent<RouteParams>;`);
|
|
330
|
+
exports.push(`export type RequestEvent = Kit.RequestEvent<RouteParams, RouteId>;`);
|
|
314
331
|
}
|
|
315
332
|
|
|
316
333
|
const output = [imports.join('\n'), declarations.join('\n'), exports.join('\n')]
|
|
@@ -336,6 +353,8 @@ function process_node(node, outdir, is_page, proxies, all_pages_have_load = true
|
|
|
336
353
|
const params = `${is_page ? 'Route' : 'Layout'}Params`;
|
|
337
354
|
const prefix = is_page ? 'Page' : 'Layout';
|
|
338
355
|
|
|
356
|
+
const route_id = is_page ? 'RouteId' : 'LayoutRouteId';
|
|
357
|
+
|
|
339
358
|
/** @type {string[]} */
|
|
340
359
|
const declarations = [];
|
|
341
360
|
/** @type {string[]} */
|
|
@@ -367,7 +386,7 @@ function process_node(node, outdir, is_page, proxies, all_pages_have_load = true
|
|
|
367
386
|
? `Partial<App.PageData> & Record<string, any> | void`
|
|
368
387
|
: `OutputDataShape<${parent_type}>`;
|
|
369
388
|
exports.push(
|
|
370
|
-
`export type ${prefix}ServerLoad<OutputData extends ${output_data_shape} = ${output_data_shape}> = Kit.ServerLoad<${params}, ${parent_type}, OutputData>;`
|
|
389
|
+
`export type ${prefix}ServerLoad<OutputData extends ${output_data_shape} = ${output_data_shape}> = Kit.ServerLoad<${params}, ${parent_type}, OutputData, ${route_id}>;`
|
|
371
390
|
);
|
|
372
391
|
|
|
373
392
|
exports.push(`export type ${prefix}ServerLoadEvent = Parameters<${prefix}ServerLoad>[0];`);
|
|
@@ -414,7 +433,7 @@ function process_node(node, outdir, is_page, proxies, all_pages_have_load = true
|
|
|
414
433
|
? `Partial<App.PageData> & Record<string, any> | void`
|
|
415
434
|
: `OutputDataShape<${parent_type}>`;
|
|
416
435
|
exports.push(
|
|
417
|
-
`export type ${prefix}Load<OutputData extends ${output_data_shape} = ${output_data_shape}> = Kit.Load<${params}, ${prefix}ServerData, ${parent_type}, OutputData>;`
|
|
436
|
+
`export type ${prefix}Load<OutputData extends ${output_data_shape} = ${output_data_shape}> = Kit.Load<${params}, ${prefix}ServerData, ${parent_type}, OutputData, ${route_id}>;`
|
|
418
437
|
);
|
|
419
438
|
|
|
420
439
|
exports.push(`export type ${prefix}LoadEvent = Parameters<${prefix}Load>[0];`);
|
|
@@ -74,7 +74,7 @@ export class Server {
|
|
|
74
74
|
get request() {
|
|
75
75
|
throw new Error('request in handleError has been replaced with event. See https://github.com/sveltejs/kit/pull/3384 for details');
|
|
76
76
|
}
|
|
77
|
-
}) ?? { message: event.
|
|
77
|
+
}) ?? { message: event.route.id != null ? 'Internal Error' : 'Not Found' };
|
|
78
78
|
},
|
|
79
79
|
hooks: null,
|
|
80
80
|
manifest,
|
|
@@ -439,7 +439,7 @@ export async function dev(vite, vite_config, svelte_config) {
|
|
|
439
439
|
'request in handleError has been replaced with event. See https://github.com/sveltejs/kit/pull/3384 for details'
|
|
440
440
|
);
|
|
441
441
|
}
|
|
442
|
-
}) ?? { message: event.
|
|
442
|
+
}) ?? { message: event.route.id != null ? 'Internal Error' : 'Not Found' }
|
|
443
443
|
);
|
|
444
444
|
},
|
|
445
445
|
hooks,
|
|
@@ -163,16 +163,16 @@ export function create_client({ target, base, trailing_slash }) {
|
|
|
163
163
|
|
|
164
164
|
/**
|
|
165
165
|
* @param {string | URL} url
|
|
166
|
-
* @param {{
|
|
166
|
+
* @param {{ noScroll?: boolean; replaceState?: boolean; keepFocus?: boolean; state?: any; invalidateAll?: boolean }} opts
|
|
167
167
|
* @param {string[]} redirect_chain
|
|
168
168
|
* @param {{}} [nav_token]
|
|
169
169
|
*/
|
|
170
170
|
async function goto(
|
|
171
171
|
url,
|
|
172
172
|
{
|
|
173
|
-
|
|
173
|
+
noScroll = false,
|
|
174
174
|
replaceState = false,
|
|
175
|
-
|
|
175
|
+
keepFocus = false,
|
|
176
176
|
state = {},
|
|
177
177
|
invalidateAll = false
|
|
178
178
|
},
|
|
@@ -185,8 +185,8 @@ export function create_client({ target, base, trailing_slash }) {
|
|
|
185
185
|
|
|
186
186
|
return navigate({
|
|
187
187
|
url,
|
|
188
|
-
scroll:
|
|
189
|
-
keepfocus,
|
|
188
|
+
scroll: noScroll ? scroll_state() : null,
|
|
189
|
+
keepfocus: keepFocus,
|
|
190
190
|
redirect_chain,
|
|
191
191
|
details: {
|
|
192
192
|
state,
|
|
@@ -232,8 +232,12 @@ export function create_client({ target, base, trailing_slash }) {
|
|
|
232
232
|
if (!navigation_result) {
|
|
233
233
|
navigation_result = await server_fallback(
|
|
234
234
|
url,
|
|
235
|
-
null,
|
|
236
|
-
handle_error(new Error(`Not found: ${url.pathname}`), {
|
|
235
|
+
{ id: null },
|
|
236
|
+
handle_error(new Error(`Not found: ${url.pathname}`), {
|
|
237
|
+
url,
|
|
238
|
+
params: {},
|
|
239
|
+
route: { id: null }
|
|
240
|
+
}),
|
|
237
241
|
404
|
|
238
242
|
);
|
|
239
243
|
}
|
|
@@ -249,9 +253,9 @@ export function create_client({ target, base, trailing_slash }) {
|
|
|
249
253
|
if (redirect_chain.length > 10 || redirect_chain.includes(url.pathname)) {
|
|
250
254
|
navigation_result = await load_root_error_page({
|
|
251
255
|
status: 500,
|
|
252
|
-
error: handle_error(new Error('Redirect loop'), { url, params: {},
|
|
256
|
+
error: handle_error(new Error('Redirect loop'), { url, params: {}, route: { id: null } }),
|
|
253
257
|
url,
|
|
254
|
-
|
|
258
|
+
route: { id: null }
|
|
255
259
|
});
|
|
256
260
|
} else {
|
|
257
261
|
goto(
|
|
@@ -382,7 +386,7 @@ export function create_client({ target, base, trailing_slash }) {
|
|
|
382
386
|
from: null,
|
|
383
387
|
to: add_url_properties('to', {
|
|
384
388
|
params: current.params,
|
|
385
|
-
|
|
389
|
+
route: { id: current.route?.id ?? null },
|
|
386
390
|
url: new URL(location.href)
|
|
387
391
|
}),
|
|
388
392
|
type: 'load'
|
|
@@ -464,7 +468,7 @@ export function create_client({ target, base, trailing_slash }) {
|
|
|
464
468
|
result.props.page = {
|
|
465
469
|
error,
|
|
466
470
|
params,
|
|
467
|
-
|
|
471
|
+
route,
|
|
468
472
|
status,
|
|
469
473
|
url,
|
|
470
474
|
form,
|
|
@@ -502,12 +506,12 @@ export function create_client({ target, base, trailing_slash }) {
|
|
|
502
506
|
* parent: () => Promise<Record<string, any>>;
|
|
503
507
|
* url: URL;
|
|
504
508
|
* params: Record<string, string>;
|
|
505
|
-
*
|
|
509
|
+
* route: { id: string | null };
|
|
506
510
|
* server_data_node: import('./types').DataNode | null;
|
|
507
511
|
* }} options
|
|
508
512
|
* @returns {Promise<import('./types').BranchNode>}
|
|
509
513
|
*/
|
|
510
|
-
async function load_node({ loader, parent, url, params,
|
|
514
|
+
async function load_node({ loader, parent, url, params, route, server_data_node }) {
|
|
511
515
|
/** @type {Record<string, any> | null} */
|
|
512
516
|
let data = null;
|
|
513
517
|
|
|
@@ -516,6 +520,7 @@ export function create_client({ target, base, trailing_slash }) {
|
|
|
516
520
|
dependencies: new Set(),
|
|
517
521
|
params: new Set(),
|
|
518
522
|
parent: false,
|
|
523
|
+
route: false,
|
|
519
524
|
url: false
|
|
520
525
|
};
|
|
521
526
|
|
|
@@ -532,7 +537,12 @@ export function create_client({ target, base, trailing_slash }) {
|
|
|
532
537
|
|
|
533
538
|
/** @type {import('types').LoadEvent} */
|
|
534
539
|
const load_input = {
|
|
535
|
-
|
|
540
|
+
route: {
|
|
541
|
+
get id() {
|
|
542
|
+
uses.route = true;
|
|
543
|
+
return route.id;
|
|
544
|
+
}
|
|
545
|
+
},
|
|
536
546
|
params: new Proxy(params, {
|
|
537
547
|
get: (target, key) => {
|
|
538
548
|
uses.params.add(/** @type {string} */ (key));
|
|
@@ -617,6 +627,12 @@ export function create_client({ target, base, trailing_slash }) {
|
|
|
617
627
|
);
|
|
618
628
|
},
|
|
619
629
|
enumerable: false
|
|
630
|
+
},
|
|
631
|
+
routeId: {
|
|
632
|
+
get() {
|
|
633
|
+
throw new Error('routeId has been replaced by route.id');
|
|
634
|
+
},
|
|
635
|
+
enumerable: false
|
|
620
636
|
}
|
|
621
637
|
});
|
|
622
638
|
|
|
@@ -643,17 +659,19 @@ export function create_client({ target, base, trailing_slash }) {
|
|
|
643
659
|
}
|
|
644
660
|
|
|
645
661
|
/**
|
|
646
|
-
* @param {boolean} url_changed
|
|
647
662
|
* @param {boolean} parent_changed
|
|
663
|
+
* @param {boolean} route_changed
|
|
664
|
+
* @param {boolean} url_changed
|
|
648
665
|
* @param {import('types').Uses | undefined} uses
|
|
649
666
|
* @param {Record<string, string>} params
|
|
650
667
|
*/
|
|
651
|
-
function has_changed(
|
|
668
|
+
function has_changed(parent_changed, route_changed, url_changed, uses, params) {
|
|
652
669
|
if (force_invalidation) return true;
|
|
653
670
|
|
|
654
671
|
if (!uses) return false;
|
|
655
672
|
|
|
656
673
|
if (uses.parent && parent_changed) return true;
|
|
674
|
+
if (uses.route && route_changed) return true;
|
|
657
675
|
if (uses.url && url_changed) return true;
|
|
658
676
|
|
|
659
677
|
for (const param of uses.params) {
|
|
@@ -681,6 +699,7 @@ export function create_client({ target, base, trailing_slash }) {
|
|
|
681
699
|
dependencies: new Set(node.uses.dependencies ?? []),
|
|
682
700
|
params: new Set(node.uses.params ?? []),
|
|
683
701
|
parent: !!node.uses.parent,
|
|
702
|
+
route: !!node.uses.route,
|
|
684
703
|
url: !!node.uses.url
|
|
685
704
|
}
|
|
686
705
|
};
|
|
@@ -713,6 +732,7 @@ export function create_client({ target, base, trailing_slash }) {
|
|
|
713
732
|
let server_data = null;
|
|
714
733
|
|
|
715
734
|
const url_changed = current.url ? id !== current.url.pathname + current.url.search : false;
|
|
735
|
+
const route_changed = current.route ? id !== current.route.id : false;
|
|
716
736
|
|
|
717
737
|
const invalid_server_nodes = loaders.reduce((acc, loader, i) => {
|
|
718
738
|
const previous = current.branch[i];
|
|
@@ -720,7 +740,13 @@ export function create_client({ target, base, trailing_slash }) {
|
|
|
720
740
|
const invalid =
|
|
721
741
|
!!loader?.[0] &&
|
|
722
742
|
(previous?.loader !== loader[1] ||
|
|
723
|
-
has_changed(
|
|
743
|
+
has_changed(
|
|
744
|
+
acc.some(Boolean),
|
|
745
|
+
route_changed,
|
|
746
|
+
url_changed,
|
|
747
|
+
previous.server?.uses,
|
|
748
|
+
params
|
|
749
|
+
));
|
|
724
750
|
|
|
725
751
|
acc.push(invalid);
|
|
726
752
|
return acc;
|
|
@@ -732,9 +758,9 @@ export function create_client({ target, base, trailing_slash }) {
|
|
|
732
758
|
} catch (error) {
|
|
733
759
|
return load_root_error_page({
|
|
734
760
|
status: 500,
|
|
735
|
-
error: handle_error(error, { url, params,
|
|
761
|
+
error: handle_error(error, { url, params, route: { id: route.id } }),
|
|
736
762
|
url,
|
|
737
|
-
|
|
763
|
+
route
|
|
738
764
|
});
|
|
739
765
|
}
|
|
740
766
|
|
|
@@ -759,7 +785,7 @@ export function create_client({ target, base, trailing_slash }) {
|
|
|
759
785
|
const valid =
|
|
760
786
|
(!server_data_node || server_data_node.type === 'skip') &&
|
|
761
787
|
loader[1] === previous?.loader &&
|
|
762
|
-
!has_changed(
|
|
788
|
+
!has_changed(parent_changed, route_changed, url_changed, previous.shared?.uses, params);
|
|
763
789
|
if (valid) return previous;
|
|
764
790
|
|
|
765
791
|
parent_changed = true;
|
|
@@ -773,7 +799,7 @@ export function create_client({ target, base, trailing_slash }) {
|
|
|
773
799
|
loader: loader[1],
|
|
774
800
|
url,
|
|
775
801
|
params,
|
|
776
|
-
|
|
802
|
+
route,
|
|
777
803
|
parent: async () => {
|
|
778
804
|
const data = {};
|
|
779
805
|
for (let j = 0; j < i; j += 1) {
|
|
@@ -821,7 +847,7 @@ export function create_client({ target, base, trailing_slash }) {
|
|
|
821
847
|
status = err.status;
|
|
822
848
|
error = err.body;
|
|
823
849
|
} else {
|
|
824
|
-
error = handle_error(err, { params, url,
|
|
850
|
+
error = handle_error(err, { params, url, route: { id: route.id } });
|
|
825
851
|
}
|
|
826
852
|
|
|
827
853
|
const error_load = await load_nearest_error_page(i, branch, errors);
|
|
@@ -837,7 +863,7 @@ export function create_client({ target, base, trailing_slash }) {
|
|
|
837
863
|
} else {
|
|
838
864
|
// if we get here, it's because the root `load` function failed,
|
|
839
865
|
// and we need to fall back to the server
|
|
840
|
-
return await server_fallback(url, route.id, error, status);
|
|
866
|
+
return await server_fallback(url, { id: route.id }, error, status);
|
|
841
867
|
}
|
|
842
868
|
}
|
|
843
869
|
} else {
|
|
@@ -893,11 +919,11 @@ export function create_client({ target, base, trailing_slash }) {
|
|
|
893
919
|
* status: number;
|
|
894
920
|
* error: App.Error;
|
|
895
921
|
* url: URL;
|
|
896
|
-
*
|
|
922
|
+
* route: { id: string | null }
|
|
897
923
|
* }} opts
|
|
898
924
|
* @returns {Promise<import('./types').NavigationFinished>}
|
|
899
925
|
*/
|
|
900
|
-
async function load_root_error_page({ status, error, url,
|
|
926
|
+
async function load_root_error_page({ status, error, url, route }) {
|
|
901
927
|
/** @type {Record<string, string>} */
|
|
902
928
|
const params = {}; // error page does not have params
|
|
903
929
|
|
|
@@ -933,7 +959,7 @@ export function create_client({ target, base, trailing_slash }) {
|
|
|
933
959
|
loader: default_layout_loader,
|
|
934
960
|
url,
|
|
935
961
|
params,
|
|
936
|
-
|
|
962
|
+
route,
|
|
937
963
|
parent: () => Promise.resolve({}),
|
|
938
964
|
server_data_node: create_data_node(server_data_node)
|
|
939
965
|
});
|
|
@@ -1023,12 +1049,12 @@ export function create_client({ target, base, trailing_slash }) {
|
|
|
1023
1049
|
const navigation = {
|
|
1024
1050
|
from: add_url_properties('from', {
|
|
1025
1051
|
params: current.params,
|
|
1026
|
-
|
|
1052
|
+
route: { id: current.route?.id ?? null },
|
|
1027
1053
|
url: current.url
|
|
1028
1054
|
}),
|
|
1029
1055
|
to: add_url_properties('to', {
|
|
1030
1056
|
params: intent?.params ?? null,
|
|
1031
|
-
|
|
1057
|
+
route: { id: intent?.route?.id ?? null },
|
|
1032
1058
|
url
|
|
1033
1059
|
}),
|
|
1034
1060
|
type
|
|
@@ -1080,12 +1106,12 @@ export function create_client({ target, base, trailing_slash }) {
|
|
|
1080
1106
|
/**
|
|
1081
1107
|
* Does a full page reload if it wouldn't result in an endless loop in the SPA case
|
|
1082
1108
|
* @param {URL} url
|
|
1083
|
-
* @param {string | null}
|
|
1109
|
+
* @param {{ id: string | null }} route
|
|
1084
1110
|
* @param {App.Error} error
|
|
1085
1111
|
* @param {number} status
|
|
1086
1112
|
* @returns {Promise<import('./types').NavigationFinished>}
|
|
1087
1113
|
*/
|
|
1088
|
-
async function server_fallback(url,
|
|
1114
|
+
async function server_fallback(url, route, error, status) {
|
|
1089
1115
|
if (url.origin === location.origin && url.pathname === location.pathname && !hydrated) {
|
|
1090
1116
|
// We would reload the same page we're currently on, which isn't hydrated,
|
|
1091
1117
|
// which means no SSR, which means we would end up in an endless loop
|
|
@@ -1093,7 +1119,7 @@ export function create_client({ target, base, trailing_slash }) {
|
|
|
1093
1119
|
status,
|
|
1094
1120
|
error,
|
|
1095
1121
|
url,
|
|
1096
|
-
|
|
1122
|
+
route
|
|
1097
1123
|
});
|
|
1098
1124
|
}
|
|
1099
1125
|
return await native_navigation(url);
|
|
@@ -1149,7 +1175,22 @@ export function create_client({ target, base, trailing_slash }) {
|
|
|
1149
1175
|
}
|
|
1150
1176
|
},
|
|
1151
1177
|
|
|
1152
|
-
goto: (href, opts = {}) =>
|
|
1178
|
+
goto: (href, opts = {}) => {
|
|
1179
|
+
// TODO remove for 1.0
|
|
1180
|
+
if ('keepfocus' in opts) {
|
|
1181
|
+
throw new Error(
|
|
1182
|
+
'`keepfocus` has been renamed to `keepFocus` (note the difference in casing)'
|
|
1183
|
+
);
|
|
1184
|
+
}
|
|
1185
|
+
|
|
1186
|
+
if ('noscroll' in opts) {
|
|
1187
|
+
throw new Error(
|
|
1188
|
+
'`noscroll` has been renamed to `noScroll` (note the difference in casing)'
|
|
1189
|
+
);
|
|
1190
|
+
}
|
|
1191
|
+
|
|
1192
|
+
return goto(href, opts, []);
|
|
1193
|
+
},
|
|
1153
1194
|
|
|
1154
1195
|
invalidate: (resource) => {
|
|
1155
1196
|
if (resource === undefined) {
|
|
@@ -1248,7 +1289,7 @@ export function create_client({ target, base, trailing_slash }) {
|
|
|
1248
1289
|
const navigation = {
|
|
1249
1290
|
from: add_url_properties('from', {
|
|
1250
1291
|
params: current.params,
|
|
1251
|
-
|
|
1292
|
+
route: { id: current.route?.id ?? null },
|
|
1252
1293
|
url: current.url
|
|
1253
1294
|
}),
|
|
1254
1295
|
to: null,
|
|
@@ -1437,15 +1478,7 @@ export function create_client({ target, base, trailing_slash }) {
|
|
|
1437
1478
|
});
|
|
1438
1479
|
},
|
|
1439
1480
|
|
|
1440
|
-
_hydrate: async ({
|
|
1441
|
-
status,
|
|
1442
|
-
error,
|
|
1443
|
-
node_ids,
|
|
1444
|
-
params,
|
|
1445
|
-
routeId,
|
|
1446
|
-
data: server_data_nodes,
|
|
1447
|
-
form
|
|
1448
|
-
}) => {
|
|
1481
|
+
_hydrate: async ({ status, error, node_ids, params, route, data: server_data_nodes, form }) => {
|
|
1449
1482
|
hydrated = true;
|
|
1450
1483
|
|
|
1451
1484
|
const url = new URL(location.href);
|
|
@@ -1461,7 +1494,7 @@ export function create_client({ target, base, trailing_slash }) {
|
|
|
1461
1494
|
loader: nodes[n],
|
|
1462
1495
|
url,
|
|
1463
1496
|
params,
|
|
1464
|
-
|
|
1497
|
+
route,
|
|
1465
1498
|
parent: async () => {
|
|
1466
1499
|
const data = {};
|
|
1467
1500
|
for (let j = 0; j < i; j += 1) {
|
|
@@ -1480,7 +1513,7 @@ export function create_client({ target, base, trailing_slash }) {
|
|
|
1480
1513
|
status,
|
|
1481
1514
|
error,
|
|
1482
1515
|
form,
|
|
1483
|
-
route: routes.find((
|
|
1516
|
+
route: routes.find(({ id }) => id === route.id) ?? null
|
|
1484
1517
|
});
|
|
1485
1518
|
} catch (error) {
|
|
1486
1519
|
if (error instanceof Redirect) {
|
|
@@ -1492,9 +1525,9 @@ export function create_client({ target, base, trailing_slash }) {
|
|
|
1492
1525
|
|
|
1493
1526
|
result = await load_root_error_page({
|
|
1494
1527
|
status: error instanceof HttpError ? error.status : 500,
|
|
1495
|
-
error: handle_error(error, { url, params,
|
|
1528
|
+
error: handle_error(error, { url, params, route }),
|
|
1496
1529
|
url,
|
|
1497
|
-
|
|
1530
|
+
route
|
|
1498
1531
|
});
|
|
1499
1532
|
}
|
|
1500
1533
|
|
|
@@ -1517,14 +1550,28 @@ async function load_data(url, invalid) {
|
|
|
1517
1550
|
'x-sveltekit-invalidated': invalid.map((x) => (x ? '1' : '')).join(',')
|
|
1518
1551
|
}
|
|
1519
1552
|
});
|
|
1520
|
-
const
|
|
1553
|
+
const data = await res.json();
|
|
1521
1554
|
|
|
1522
1555
|
if (!res.ok) {
|
|
1523
1556
|
// error message is a JSON-stringified string which devalue can't handle at the top level
|
|
1524
|
-
throw new Error(
|
|
1557
|
+
throw new Error(data);
|
|
1525
1558
|
}
|
|
1526
1559
|
|
|
1527
|
-
|
|
1560
|
+
// revive devalue-flattened data
|
|
1561
|
+
data.nodes?.forEach((/** @type {any} */ node) => {
|
|
1562
|
+
if (node?.type === 'data') {
|
|
1563
|
+
node.data = devalue.unflatten(node.data);
|
|
1564
|
+
node.uses = {
|
|
1565
|
+
dependencies: new Set(node.uses.dependencies ?? []),
|
|
1566
|
+
params: new Set(node.uses.params ?? []),
|
|
1567
|
+
parent: !!node.uses.parent,
|
|
1568
|
+
route: !!node.uses.route,
|
|
1569
|
+
url: !!node.uses.url
|
|
1570
|
+
};
|
|
1571
|
+
}
|
|
1572
|
+
});
|
|
1573
|
+
|
|
1574
|
+
return data;
|
|
1528
1575
|
}
|
|
1529
1576
|
|
|
1530
1577
|
/**
|
|
@@ -1538,7 +1585,7 @@ function handle_error(error, event) {
|
|
|
1538
1585
|
}
|
|
1539
1586
|
return (
|
|
1540
1587
|
hooks.handleError({ error, event }) ??
|
|
1541
|
-
/** @type {any} */ ({ message: event.
|
|
1588
|
+
/** @type {any} */ ({ message: event.route.id != null ? 'Internal Error' : 'Not Found' })
|
|
1542
1589
|
);
|
|
1543
1590
|
}
|
|
1544
1591
|
|
|
@@ -1574,6 +1621,15 @@ function add_url_properties(type, target) {
|
|
|
1574
1621
|
});
|
|
1575
1622
|
}
|
|
1576
1623
|
|
|
1624
|
+
Object.defineProperty(target, 'routeId', {
|
|
1625
|
+
get() {
|
|
1626
|
+
throw new Error(
|
|
1627
|
+
`The navigation shape changed - ${type}.routeId should now be ${type}.route.id`
|
|
1628
|
+
);
|
|
1629
|
+
},
|
|
1630
|
+
enumerable: false
|
|
1631
|
+
});
|
|
1632
|
+
|
|
1577
1633
|
return target;
|
|
1578
1634
|
}
|
|
1579
1635
|
|
|
@@ -28,7 +28,7 @@ export interface Client {
|
|
|
28
28
|
error: App.Error;
|
|
29
29
|
node_ids: number[];
|
|
30
30
|
params: Record<string, string>;
|
|
31
|
-
|
|
31
|
+
route: { id: string | null };
|
|
32
32
|
data: Array<import('types').ServerDataNode | null>;
|
|
33
33
|
form: Record<string, any> | null;
|
|
34
34
|
}): Promise<void>;
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
+
import * as devalue from 'devalue';
|
|
1
2
|
import { HttpError, Redirect } from '../../control.js';
|
|
2
3
|
import { normalize_error } from '../../../utils/error.js';
|
|
3
4
|
import { once } from '../../../utils/functions.js';
|
|
4
5
|
import { load_server_data } from '../page/load_data.js';
|
|
5
|
-
import {
|
|
6
|
+
import { clarify_devalue_error, handle_error_and_jsonify, serialize_data_node } from '../utils.js';
|
|
6
7
|
import { normalize_path, strip_data_suffix } from '../../../utils/url.js';
|
|
7
8
|
|
|
8
9
|
/**
|
|
@@ -101,27 +102,42 @@ export async function render_data(event, route, options, state) {
|
|
|
101
102
|
)
|
|
102
103
|
);
|
|
103
104
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
type: 'data',
|
|
107
|
-
nodes: nodes.slice(0, length)
|
|
108
|
-
};
|
|
105
|
+
try {
|
|
106
|
+
const stubs = nodes.slice(0, length).map(serialize_data_node);
|
|
109
107
|
|
|
110
|
-
|
|
108
|
+
const json = `{"type":"data","nodes":[${stubs.join(',')}]}`;
|
|
109
|
+
return json_response(json);
|
|
110
|
+
} catch (e) {
|
|
111
|
+
const error = /** @type {any} */ (e);
|
|
112
|
+
return json_response(JSON.stringify(clarify_devalue_error(event, error)), 500);
|
|
113
|
+
}
|
|
111
114
|
} catch (e) {
|
|
112
115
|
const error = normalize_error(e);
|
|
113
116
|
|
|
114
117
|
if (error instanceof Redirect) {
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
return data_response(server_data, event);
|
|
118
|
+
return json_response(
|
|
119
|
+
JSON.stringify({
|
|
120
|
+
type: 'redirect',
|
|
121
|
+
location: error.location
|
|
122
|
+
})
|
|
123
|
+
);
|
|
122
124
|
} else {
|
|
123
125
|
// TODO make it clearer that this was an unexpected error
|
|
124
|
-
return
|
|
126
|
+
return json_response(JSON.stringify(handle_error_and_jsonify(event, options, error)));
|
|
125
127
|
}
|
|
126
128
|
}
|
|
127
129
|
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* @param {string} json
|
|
133
|
+
* @param {number} [status]
|
|
134
|
+
*/
|
|
135
|
+
function json_response(json, status = 200) {
|
|
136
|
+
return new Response(json, {
|
|
137
|
+
status,
|
|
138
|
+
headers: {
|
|
139
|
+
'content-type': 'application/json',
|
|
140
|
+
'cache-control': 'private, no-store'
|
|
141
|
+
}
|
|
142
|
+
});
|
|
143
|
+
}
|
|
@@ -34,7 +34,7 @@ export async function render_endpoint(event, mod, state) {
|
|
|
34
34
|
if (state.prerendering && !prerender) {
|
|
35
35
|
if (state.initiator) {
|
|
36
36
|
// if request came from a prerendered page, bail
|
|
37
|
-
throw new Error(`${event.
|
|
37
|
+
throw new Error(`${event.route.id} is not prerenderable`);
|
|
38
38
|
} else {
|
|
39
39
|
// if request came direct from the crawler, signal that
|
|
40
40
|
// this route cannot be prerendered, but don't bail
|
|
@@ -121,7 +121,7 @@ export async function respond(request, options, state) {
|
|
|
121
121
|
params,
|
|
122
122
|
platform: state.platform,
|
|
123
123
|
request,
|
|
124
|
-
|
|
124
|
+
route: { id: route?.id ?? null },
|
|
125
125
|
setHeaders: (new_headers) => {
|
|
126
126
|
for (const key in new_headers) {
|
|
127
127
|
const lower = key.toLowerCase();
|
|
@@ -178,7 +178,8 @@ export async function respond(request, options, state) {
|
|
|
178
178
|
path: removed('path', 'url.pathname'),
|
|
179
179
|
query: removed('query', 'url.searchParams'),
|
|
180
180
|
body: body_getter,
|
|
181
|
-
rawBody: body_getter
|
|
181
|
+
rawBody: body_getter,
|
|
182
|
+
routeId: removed('routeId', 'route.id')
|
|
182
183
|
});
|
|
183
184
|
|
|
184
185
|
/** @type {import('types').RequiredResolveOptions} */
|
|
@@ -305,8 +306,8 @@ export async function respond(request, options, state) {
|
|
|
305
306
|
}
|
|
306
307
|
add_cookies_to_headers(response.headers, Object.values(new_cookies));
|
|
307
308
|
|
|
308
|
-
if (state.prerendering && event.
|
|
309
|
-
response.headers.set('x-sveltekit-routeid', encodeURI(event.
|
|
309
|
+
if (state.prerendering && event.route.id !== null) {
|
|
310
|
+
response.headers.set('x-sveltekit-routeid', encodeURI(event.route.id));
|
|
310
311
|
}
|
|
311
312
|
|
|
312
313
|
return response;
|
|
@@ -41,10 +41,10 @@ export async function handle_action_json_request(event, options, server) {
|
|
|
41
41
|
const data = await call_action(event, actions);
|
|
42
42
|
|
|
43
43
|
if (data instanceof ValidationError) {
|
|
44
|
-
check_serializability(data.data, /** @type {string} */ (event.
|
|
44
|
+
check_serializability(data.data, /** @type {string} */ (event.route.id), 'data');
|
|
45
45
|
return action_json({ type: 'invalid', status: data.status, data: data.data });
|
|
46
46
|
} else {
|
|
47
|
-
check_serializability(data, /** @type {string} */ (event.
|
|
47
|
+
check_serializability(data, /** @type {string} */ (event.route.id), 'data');
|
|
48
48
|
return action_json({
|
|
49
49
|
type: 'success',
|
|
50
50
|
status: data ? 200 : 204,
|
|
@@ -7,7 +7,8 @@ import {
|
|
|
7
7
|
get_option,
|
|
8
8
|
redirect_response,
|
|
9
9
|
static_error_page,
|
|
10
|
-
handle_error_and_jsonify
|
|
10
|
+
handle_error_and_jsonify,
|
|
11
|
+
serialize_data_node
|
|
11
12
|
} from '../utils.js';
|
|
12
13
|
import {
|
|
13
14
|
handle_action_json_request,
|
|
@@ -208,7 +209,7 @@ export async function render_page(event, route, page, options, state, resolve_op
|
|
|
208
209
|
|
|
209
210
|
if (err instanceof Redirect) {
|
|
210
211
|
if (state.prerendering && should_prerender_data) {
|
|
211
|
-
const body =
|
|
212
|
+
const body = JSON.stringify({
|
|
212
213
|
type: 'redirect',
|
|
213
214
|
location: err.location
|
|
214
215
|
});
|
|
@@ -263,10 +264,9 @@ export async function render_page(event, route, page, options, state, resolve_op
|
|
|
263
264
|
}
|
|
264
265
|
|
|
265
266
|
if (state.prerendering && should_prerender_data) {
|
|
266
|
-
const body =
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
});
|
|
267
|
+
const body = `{"type":"data","nodes":[${branch
|
|
268
|
+
.map((node) => serialize_data_node(node?.server_data))
|
|
269
|
+
.join(',')}]}`;
|
|
270
270
|
|
|
271
271
|
state.prerendering.dependencies.set(data_pathname, {
|
|
272
272
|
response: new Response(body),
|
|
@@ -17,6 +17,7 @@ export async function load_server_data({ event, state, node, parent }) {
|
|
|
17
17
|
dependencies: new Set(),
|
|
18
18
|
params: new Set(),
|
|
19
19
|
parent: false,
|
|
20
|
+
route: false,
|
|
20
21
|
url: false
|
|
21
22
|
};
|
|
22
23
|
|
|
@@ -47,6 +48,12 @@ export async function load_server_data({ event, state, node, parent }) {
|
|
|
47
48
|
uses.parent = true;
|
|
48
49
|
return parent();
|
|
49
50
|
},
|
|
51
|
+
route: {
|
|
52
|
+
get id() {
|
|
53
|
+
uses.route = true;
|
|
54
|
+
return event.route.id;
|
|
55
|
+
}
|
|
56
|
+
},
|
|
50
57
|
url
|
|
51
58
|
});
|
|
52
59
|
|
|
@@ -55,12 +62,7 @@ export async function load_server_data({ event, state, node, parent }) {
|
|
|
55
62
|
return {
|
|
56
63
|
type: 'data',
|
|
57
64
|
data,
|
|
58
|
-
uses
|
|
59
|
-
dependencies: uses.dependencies.size > 0 ? Array.from(uses.dependencies) : undefined,
|
|
60
|
-
params: uses.params.size > 0 ? Array.from(uses.params) : undefined,
|
|
61
|
-
parent: uses.parent ? 1 : undefined,
|
|
62
|
-
url: uses.url ? 1 : undefined
|
|
63
|
-
}
|
|
65
|
+
uses
|
|
64
66
|
};
|
|
65
67
|
}
|
|
66
68
|
|
|
@@ -99,7 +101,7 @@ export async function load_data({
|
|
|
99
101
|
url: event.url,
|
|
100
102
|
params: event.params,
|
|
101
103
|
data: server_data_node?.data ?? null,
|
|
102
|
-
|
|
104
|
+
route: event.route,
|
|
103
105
|
fetch: async (input, init) => {
|
|
104
106
|
const response = await event.fetch(input, init);
|
|
105
107
|
|
|
@@ -199,7 +201,7 @@ export async function load_data({
|
|
|
199
201
|
const included = resolve_opts.filterSerializedResponseHeaders(lower, value);
|
|
200
202
|
if (!included) {
|
|
201
203
|
throw new Error(
|
|
202
|
-
`Failed to get response header "${lower}" — it must be included by the \`filterSerializedResponseHeaders\` option: https://kit.svelte.dev/docs/hooks#server-hooks-handle (at ${event.
|
|
204
|
+
`Failed to get response header "${lower}" — it must be included by the \`filterSerializedResponseHeaders\` option: https://kit.svelte.dev/docs/hooks#server-hooks-handle (at ${event.route})`
|
|
203
205
|
);
|
|
204
206
|
}
|
|
205
207
|
}
|
|
@@ -4,6 +4,7 @@ import { hash } from '../../hash.js';
|
|
|
4
4
|
import { serialize_data } from './serialize_data.js';
|
|
5
5
|
import { s } from '../../../utils/misc.js';
|
|
6
6
|
import { Csp } from './csp.js';
|
|
7
|
+
import { clarify_devalue_error } from '../utils.js';
|
|
7
8
|
|
|
8
9
|
// TODO rename this function/module
|
|
9
10
|
|
|
@@ -92,7 +93,7 @@ export async function render_response({
|
|
|
92
93
|
props.page = {
|
|
93
94
|
error,
|
|
94
95
|
params: /** @type {Record<string, any>} */ (event.params),
|
|
95
|
-
|
|
96
|
+
route: event.route,
|
|
96
97
|
status,
|
|
97
98
|
url: event.url,
|
|
98
99
|
data,
|
|
@@ -170,33 +171,33 @@ export async function render_response({
|
|
|
170
171
|
const serialized = { data: '', form: 'null' };
|
|
171
172
|
|
|
172
173
|
try {
|
|
173
|
-
serialized.data =
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
// function, but it would mean passing more stuff around than we currently do
|
|
178
|
-
const error = /** @type {any} */ (e);
|
|
179
|
-
const match = /\[(\d+)\]\.data\.(.+)/.exec(error.path);
|
|
180
|
-
if (match) {
|
|
181
|
-
throw new Error(
|
|
182
|
-
`Data returned from \`load\` while rendering ${event.routeId} is not serializable: ${error.message} (data.${match[2]})`
|
|
183
|
-
);
|
|
184
|
-
}
|
|
174
|
+
serialized.data = `[${branch
|
|
175
|
+
.map(({ server_data }) => {
|
|
176
|
+
if (server_data?.type === 'data') {
|
|
177
|
+
const data = devalue.uneval(server_data.data);
|
|
185
178
|
|
|
186
|
-
|
|
179
|
+
const uses = [];
|
|
180
|
+
if (server_data.uses.dependencies.size > 0) {
|
|
181
|
+
uses.push(`dependencies:${s(Array.from(server_data.uses.dependencies))}`);
|
|
182
|
+
}
|
|
187
183
|
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
184
|
+
if (server_data.uses.params.size > 0) {
|
|
185
|
+
uses.push(`params:${s(Array.from(server_data.uses.params))}`);
|
|
186
|
+
}
|
|
191
187
|
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
}`
|
|
196
|
-
);
|
|
197
|
-
}
|
|
188
|
+
if (server_data.uses.parent) uses.push(`parent:1`);
|
|
189
|
+
if (server_data.uses.route) uses.push(`route:1`);
|
|
190
|
+
if (server_data.uses.url) uses.push(`url:1`);
|
|
198
191
|
|
|
199
|
-
|
|
192
|
+
return `{type:"data",data:${data},uses:{${uses.join(',')}}}`;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
return s(server_data);
|
|
196
|
+
})
|
|
197
|
+
.join(',')}]`;
|
|
198
|
+
} catch (e) {
|
|
199
|
+
const error = /** @type {any} */ (e);
|
|
200
|
+
throw new Error(clarify_devalue_error(event, error));
|
|
200
201
|
}
|
|
201
202
|
|
|
202
203
|
if (form_value) {
|
|
@@ -249,7 +250,7 @@ export async function render_response({
|
|
|
249
250
|
error: ${devalue.uneval(error)},
|
|
250
251
|
node_ids: [${branch.map(({ node }) => node.index).join(', ')}],
|
|
251
252
|
params: ${devalue.uneval(event.params)},
|
|
252
|
-
|
|
253
|
+
route: ${s(event.route)},
|
|
253
254
|
data: ${serialized.data},
|
|
254
255
|
form: ${serialized.form}
|
|
255
256
|
}` : 'null'},
|
|
@@ -67,28 +67,6 @@ export function allowed_methods(mod) {
|
|
|
67
67
|
return allowed;
|
|
68
68
|
}
|
|
69
69
|
|
|
70
|
-
/**
|
|
71
|
-
* @param {any} data
|
|
72
|
-
* @param {import('types').RequestEvent} event
|
|
73
|
-
*/
|
|
74
|
-
export function data_response(data, event) {
|
|
75
|
-
const headers = {
|
|
76
|
-
'content-type': 'application/json',
|
|
77
|
-
'cache-control': 'private, no-store'
|
|
78
|
-
};
|
|
79
|
-
|
|
80
|
-
try {
|
|
81
|
-
return new Response(devalue.stringify(data), { headers });
|
|
82
|
-
} catch (e) {
|
|
83
|
-
const error = /** @type {any} */ (e);
|
|
84
|
-
const match = /\[(\d+)\]\.data\.(.+)/.exec(error.path);
|
|
85
|
-
const message = match
|
|
86
|
-
? `Data returned from \`load\` while rendering ${event.routeId} is not serializable: ${error.message} (data.${match[2]})`
|
|
87
|
-
: error.message;
|
|
88
|
-
return new Response(JSON.stringify(message), { headers, status: 500 });
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
|
|
92
70
|
/**
|
|
93
71
|
* @template {'prerender' | 'ssr' | 'csr'} Option
|
|
94
72
|
* @template {Option extends 'prerender' ? import('types').PrerenderOption : boolean} Value
|
|
@@ -179,3 +157,47 @@ export function redirect_response(status, location) {
|
|
|
179
157
|
});
|
|
180
158
|
return response;
|
|
181
159
|
}
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* @param {import('types').RequestEvent} event
|
|
163
|
+
* @param {Error & { path: string }} error
|
|
164
|
+
*/
|
|
165
|
+
export function clarify_devalue_error(event, error) {
|
|
166
|
+
if (error.path) {
|
|
167
|
+
return `Data returned from \`load\` while rendering ${event.route.id} is not serializable: ${error.message} (data${error.path})`;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
if (error.path === '') {
|
|
171
|
+
return `Data returned from \`load\` while rendering ${event.route.id} is not a plain object`;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
// belt and braces — this should never happen
|
|
175
|
+
return error.message;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/** @param {import('types').ServerDataNode | import('types').ServerDataSkippedNode | import('types').ServerErrorNode | null} node */
|
|
179
|
+
export function serialize_data_node(node) {
|
|
180
|
+
if (!node) return 'null';
|
|
181
|
+
|
|
182
|
+
if (node.type === 'error' || node.type === 'skip') {
|
|
183
|
+
return JSON.stringify(node);
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
const stringified = devalue.stringify(node.data);
|
|
187
|
+
|
|
188
|
+
const uses = [];
|
|
189
|
+
|
|
190
|
+
if (node.uses.dependencies.size > 0) {
|
|
191
|
+
uses.push(`"dependencies":${JSON.stringify(Array.from(node.uses.dependencies))}`);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
if (node.uses.params.size > 0) {
|
|
195
|
+
uses.push(`"params":${JSON.stringify(Array.from(node.uses.params))}`);
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
if (node.uses.parent) uses.push(`"parent":1`);
|
|
199
|
+
if (node.uses.route) uses.push(`"route":1`);
|
|
200
|
+
if (node.uses.url) uses.push(`"url":1`);
|
|
201
|
+
|
|
202
|
+
return `{"type":"data","data":${stringified},"uses":{${uses.join(',')}}}`;
|
|
203
|
+
}
|
package/types/ambient.d.ts
CHANGED
|
@@ -194,11 +194,11 @@ declare module '$app/navigation' {
|
|
|
194
194
|
/**
|
|
195
195
|
* If `true`, the browser will maintain its scroll position rather than scrolling to the top of the page after navigation
|
|
196
196
|
*/
|
|
197
|
-
|
|
197
|
+
noScroll?: boolean;
|
|
198
198
|
/**
|
|
199
199
|
* If `true`, the currently focused element will retain focus after navigation. Otherwise, focus will be reset to the body
|
|
200
200
|
*/
|
|
201
|
-
|
|
201
|
+
keepFocus?: boolean;
|
|
202
202
|
/**
|
|
203
203
|
* The state of the new/updated history entry
|
|
204
204
|
*/
|
package/types/index.d.ts
CHANGED
|
@@ -265,16 +265,18 @@ export interface Load<
|
|
|
265
265
|
Params extends Partial<Record<string, string>> = Partial<Record<string, string>>,
|
|
266
266
|
InputData extends Record<string, unknown> | null = Record<string, any> | null,
|
|
267
267
|
ParentData extends Record<string, unknown> = Record<string, any>,
|
|
268
|
-
OutputData extends Record<string, unknown> | void = Record<string, any> | void
|
|
268
|
+
OutputData extends Record<string, unknown> | void = Record<string, any> | void,
|
|
269
|
+
RouteId extends string | null = string | null
|
|
269
270
|
> {
|
|
270
|
-
(event: LoadEvent<Params, InputData, ParentData>): MaybePromise<OutputData>;
|
|
271
|
+
(event: LoadEvent<Params, InputData, ParentData, RouteId>): MaybePromise<OutputData>;
|
|
271
272
|
}
|
|
272
273
|
|
|
273
274
|
export interface LoadEvent<
|
|
274
275
|
Params extends Partial<Record<string, string>> = Partial<Record<string, string>>,
|
|
275
276
|
Data extends Record<string, unknown> | null = Record<string, any> | null,
|
|
276
|
-
ParentData extends Record<string, unknown> = Record<string, any
|
|
277
|
-
|
|
277
|
+
ParentData extends Record<string, unknown> = Record<string, any>,
|
|
278
|
+
RouteId extends string | null = string | null
|
|
279
|
+
> extends NavigationEvent<Params, RouteId> {
|
|
278
280
|
/**
|
|
279
281
|
* `fetch` is equivalent to the [native `fetch` web API](https://developer.mozilla.org/en-US/docs/Web/API/fetch), with a few additional features:
|
|
280
282
|
*
|
|
@@ -364,16 +366,22 @@ export interface LoadEvent<
|
|
|
364
366
|
}
|
|
365
367
|
|
|
366
368
|
export interface NavigationEvent<
|
|
367
|
-
Params extends Partial<Record<string, string>> = Partial<Record<string, string
|
|
369
|
+
Params extends Partial<Record<string, string>> = Partial<Record<string, string>>,
|
|
370
|
+
RouteId extends string | null = string | null
|
|
368
371
|
> {
|
|
369
372
|
/**
|
|
370
373
|
* The parameters of the current page - e.g. for a route like `/blog/[slug]`, the `slug` parameter
|
|
371
374
|
*/
|
|
372
375
|
params: Params;
|
|
373
376
|
/**
|
|
374
|
-
*
|
|
377
|
+
* Info about the current route
|
|
375
378
|
*/
|
|
376
|
-
|
|
379
|
+
route: {
|
|
380
|
+
/**
|
|
381
|
+
* The ID of the current route - e.g. for `src/routes/blog/[slug]`, it would be `blog/[slug]`
|
|
382
|
+
*/
|
|
383
|
+
id: RouteId;
|
|
384
|
+
};
|
|
377
385
|
/**
|
|
378
386
|
* The URL of the current page
|
|
379
387
|
*/
|
|
@@ -382,7 +390,7 @@ export interface NavigationEvent<
|
|
|
382
390
|
|
|
383
391
|
export interface NavigationTarget {
|
|
384
392
|
params: Record<string, string> | null;
|
|
385
|
-
|
|
393
|
+
route: { id: string | null };
|
|
386
394
|
url: URL;
|
|
387
395
|
}
|
|
388
396
|
|
|
@@ -398,7 +406,10 @@ export interface Navigation {
|
|
|
398
406
|
/**
|
|
399
407
|
* The shape of the `$page` store
|
|
400
408
|
*/
|
|
401
|
-
export interface Page<
|
|
409
|
+
export interface Page<
|
|
410
|
+
Params extends Record<string, string> = Record<string, string>,
|
|
411
|
+
RouteId extends string | null = string | null
|
|
412
|
+
> {
|
|
402
413
|
/**
|
|
403
414
|
* The URL of the current page
|
|
404
415
|
*/
|
|
@@ -408,9 +419,14 @@ export interface Page<Params extends Record<string, string> = Record<string, str
|
|
|
408
419
|
*/
|
|
409
420
|
params: Params;
|
|
410
421
|
/**
|
|
411
|
-
*
|
|
422
|
+
* Info about the current route
|
|
412
423
|
*/
|
|
413
|
-
|
|
424
|
+
route: {
|
|
425
|
+
/**
|
|
426
|
+
* The ID of the current route - e.g. for `src/routes/blog/[slug]`, it would be `blog/[slug]`
|
|
427
|
+
*/
|
|
428
|
+
id: RouteId;
|
|
429
|
+
};
|
|
414
430
|
/**
|
|
415
431
|
* Http status code of the current page
|
|
416
432
|
*/
|
|
@@ -434,7 +450,8 @@ export interface ParamMatcher {
|
|
|
434
450
|
}
|
|
435
451
|
|
|
436
452
|
export interface RequestEvent<
|
|
437
|
-
Params extends Partial<Record<string, string>> = Partial<Record<string, string
|
|
453
|
+
Params extends Partial<Record<string, string>> = Partial<Record<string, string>>,
|
|
454
|
+
RouteId extends string | null = string | null
|
|
438
455
|
> {
|
|
439
456
|
/**
|
|
440
457
|
* Get or set cookies related to the current request
|
|
@@ -471,9 +488,14 @@ export interface RequestEvent<
|
|
|
471
488
|
*/
|
|
472
489
|
request: Request;
|
|
473
490
|
/**
|
|
474
|
-
*
|
|
491
|
+
* Info about the current route
|
|
475
492
|
*/
|
|
476
|
-
|
|
493
|
+
route: {
|
|
494
|
+
/**
|
|
495
|
+
* The ID of the current route - e.g. for `src/routes/blog/[slug]`, it would be `blog/[slug]`
|
|
496
|
+
*/
|
|
497
|
+
id: RouteId;
|
|
498
|
+
};
|
|
477
499
|
/**
|
|
478
500
|
* If you need to set headers for the response, you can do so using the this method. This is useful if you want the page to be cached, for example:
|
|
479
501
|
*
|
|
@@ -509,9 +531,10 @@ export interface RequestEvent<
|
|
|
509
531
|
* It receives `Params` as the first generic argument, which you can skip by using [generated types](https://kit.svelte.dev/docs/types#generated-types) instead.
|
|
510
532
|
*/
|
|
511
533
|
export interface RequestHandler<
|
|
512
|
-
Params extends Partial<Record<string, string>> = Partial<Record<string, string
|
|
534
|
+
Params extends Partial<Record<string, string>> = Partial<Record<string, string>>,
|
|
535
|
+
RouteId extends string | null = string | null
|
|
513
536
|
> {
|
|
514
|
-
(event: RequestEvent<Params>): MaybePromise<Response>;
|
|
537
|
+
(event: RequestEvent<Params, RouteId>): MaybePromise<Response>;
|
|
515
538
|
}
|
|
516
539
|
|
|
517
540
|
export interface ResolveOptions {
|
|
@@ -555,15 +578,17 @@ export interface SSRManifest {
|
|
|
555
578
|
export interface ServerLoad<
|
|
556
579
|
Params extends Partial<Record<string, string>> = Partial<Record<string, string>>,
|
|
557
580
|
ParentData extends Record<string, any> = Record<string, any>,
|
|
558
|
-
OutputData extends Record<string, any> | void = Record<string, any> | void
|
|
581
|
+
OutputData extends Record<string, any> | void = Record<string, any> | void,
|
|
582
|
+
RouteId extends string | null = string | null
|
|
559
583
|
> {
|
|
560
|
-
(event: ServerLoadEvent<Params, ParentData>): MaybePromise<OutputData>;
|
|
584
|
+
(event: ServerLoadEvent<Params, ParentData, RouteId>): MaybePromise<OutputData>;
|
|
561
585
|
}
|
|
562
586
|
|
|
563
587
|
export interface ServerLoadEvent<
|
|
564
588
|
Params extends Partial<Record<string, string>> = Partial<Record<string, string>>,
|
|
565
|
-
ParentData extends Record<string, any> = Record<string, any
|
|
566
|
-
|
|
589
|
+
ParentData extends Record<string, any> = Record<string, any>,
|
|
590
|
+
RouteId extends string | null = string | null
|
|
591
|
+
> extends RequestEvent<Params, RouteId> {
|
|
567
592
|
/**
|
|
568
593
|
* `await parent()` returns data from parent `+layout.server.js` `load` functions.
|
|
569
594
|
*
|
|
@@ -612,15 +637,17 @@ export interface ServerLoadEvent<
|
|
|
612
637
|
|
|
613
638
|
export interface Action<
|
|
614
639
|
Params extends Partial<Record<string, string>> = Partial<Record<string, string>>,
|
|
615
|
-
OutputData extends Record<string, any> | void = Record<string, any> | void
|
|
640
|
+
OutputData extends Record<string, any> | void = Record<string, any> | void,
|
|
641
|
+
RouteId extends string | null = string | null
|
|
616
642
|
> {
|
|
617
|
-
(event: RequestEvent<Params>): MaybePromise<OutputData>;
|
|
643
|
+
(event: RequestEvent<Params, RouteId>): MaybePromise<OutputData>;
|
|
618
644
|
}
|
|
619
645
|
|
|
620
646
|
export type Actions<
|
|
621
647
|
Params extends Partial<Record<string, string>> = Partial<Record<string, string>>,
|
|
622
|
-
OutputData extends Record<string, any> | void = Record<string, any> | void
|
|
623
|
-
|
|
648
|
+
OutputData extends Record<string, any> | void = Record<string, any> | void,
|
|
649
|
+
RouteId extends string | null = string | null
|
|
650
|
+
> = Record<string, Action<Params, OutputData, RouteId>>;
|
|
624
651
|
|
|
625
652
|
/**
|
|
626
653
|
* When calling a form action via fetch, the response will be one of these shapes.
|
package/types/internal.d.ts
CHANGED
|
@@ -207,12 +207,7 @@ export type ServerData =
|
|
|
207
207
|
export interface ServerDataNode {
|
|
208
208
|
type: 'data';
|
|
209
209
|
data: Record<string, any> | null;
|
|
210
|
-
uses:
|
|
211
|
-
dependencies?: string[];
|
|
212
|
-
params?: string[];
|
|
213
|
-
parent?: number | void; // 1 or undefined
|
|
214
|
-
url?: number | void; // 1 or undefined
|
|
215
|
-
};
|
|
210
|
+
uses: Uses;
|
|
216
211
|
}
|
|
217
212
|
|
|
218
213
|
/**
|
|
@@ -362,6 +357,7 @@ export interface Uses {
|
|
|
362
357
|
dependencies: Set<string>;
|
|
363
358
|
params: Set<string>;
|
|
364
359
|
parent: boolean;
|
|
360
|
+
route: boolean;
|
|
365
361
|
url: boolean;
|
|
366
362
|
}
|
|
367
363
|
|