@sveltejs/kit 2.16.0 → 2.17.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +5 -3
- package/src/core/adapt/builder.js +2 -0
- package/src/core/config/index.js +16 -1
- package/src/core/config/options.js +2 -1
- package/src/core/generate_manifest/index.js +14 -5
- package/src/core/postbuild/analyse.js +2 -2
- package/src/core/sync/write_client_manifest.js +33 -17
- package/src/core/sync/write_server.js +2 -1
- package/src/exports/public.d.ts +29 -6
- package/src/exports/vite/build/build_server.js +5 -0
- package/src/exports/vite/dev/index.js +29 -1
- package/src/exports/vite/index.js +51 -5
- package/src/runtime/app/state/index.js +11 -0
- package/src/runtime/client/client.js +80 -46
- package/src/runtime/client/parse.js +20 -0
- package/src/runtime/client/types.d.ts +16 -1
- package/src/runtime/client/utils.js +6 -0
- package/src/runtime/pathname.js +54 -0
- package/src/runtime/server/cookie.js +2 -1
- package/src/runtime/server/endpoint.js +0 -5
- package/src/runtime/server/fetch.js +12 -0
- package/src/runtime/server/page/index.js +1 -1
- package/src/runtime/server/page/render.js +25 -3
- package/src/runtime/server/page/server_routing.js +110 -0
- package/src/runtime/server/respond.js +45 -26
- package/src/runtime/server/validate-headers.js +64 -0
- package/src/runtime/utils.js +21 -0
- package/src/types/ambient-private.d.ts +1 -0
- package/src/types/global-private.d.ts +2 -0
- package/src/types/internal.d.ts +47 -9
- package/src/utils/filesystem.js +4 -3
- package/src/utils/routing.js +8 -0
- package/src/utils/url.js +0 -23
- package/src/version.js +1 -1
- package/types/index.d.ts +72 -13
- package/types/index.d.ts.map +2 -1
|
@@ -1,19 +1,12 @@
|
|
|
1
1
|
import { DEV } from 'esm-env';
|
|
2
|
-
import { base } from '__sveltekit/paths';
|
|
2
|
+
import { base, app_dir } from '__sveltekit/paths';
|
|
3
3
|
import { is_endpoint_request, render_endpoint } from './endpoint.js';
|
|
4
4
|
import { render_page } from './page/index.js';
|
|
5
5
|
import { render_response } from './page/render.js';
|
|
6
6
|
import { respond_with_error } from './page/respond_with_error.js';
|
|
7
7
|
import { is_form_content_type } from '../../utils/http.js';
|
|
8
8
|
import { handle_fatal_error, method_not_allowed, redirect_response } from './utils.js';
|
|
9
|
-
import {
|
|
10
|
-
decode_pathname,
|
|
11
|
-
decode_params,
|
|
12
|
-
disable_search,
|
|
13
|
-
has_data_suffix,
|
|
14
|
-
normalize_path,
|
|
15
|
-
strip_data_suffix
|
|
16
|
-
} from '../../utils/url.js';
|
|
9
|
+
import { decode_pathname, decode_params, disable_search, normalize_path } from '../../utils/url.js';
|
|
17
10
|
import { exec } from '../../utils/routing.js';
|
|
18
11
|
import { redirect_json_response, render_data } from './data/index.js';
|
|
19
12
|
import { add_cookies_to_headers, get_cookies } from './cookie.js';
|
|
@@ -33,8 +26,17 @@ import { INVALIDATED_PARAM, TRAILING_SLASH_PARAM } from '../shared.js';
|
|
|
33
26
|
import { get_public_env } from './env_module.js';
|
|
34
27
|
import { load_page_nodes } from './page/load_page_nodes.js';
|
|
35
28
|
import { get_page_config } from '../../utils/route_config.js';
|
|
29
|
+
import { resolve_route } from './page/server_routing.js';
|
|
30
|
+
import { validateHeaders } from './validate-headers.js';
|
|
31
|
+
import {
|
|
32
|
+
has_data_suffix,
|
|
33
|
+
has_resolution_prefix,
|
|
34
|
+
strip_data_suffix,
|
|
35
|
+
strip_resolution_prefix
|
|
36
|
+
} from '../pathname.js';
|
|
36
37
|
|
|
37
38
|
/* global __SVELTEKIT_ADAPTER_NAME__ */
|
|
39
|
+
/* global __SVELTEKIT_DEV__ */
|
|
38
40
|
|
|
39
41
|
/** @type {import('types').RequiredResolveOptions['transformPageChunk']} */
|
|
40
42
|
const default_transform = ({ html }) => html;
|
|
@@ -85,10 +87,19 @@ export async function respond(request, options, manifest, state) {
|
|
|
85
87
|
return text('Not found', { status: 404 });
|
|
86
88
|
}
|
|
87
89
|
|
|
88
|
-
const is_data_request = has_data_suffix(url.pathname);
|
|
89
90
|
/** @type {boolean[] | undefined} */
|
|
90
91
|
let invalidated_data_nodes;
|
|
91
|
-
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* If the request is for a route resolution, first modify the URL, then continue as normal
|
|
95
|
+
* for path resolution, then return the route object as a JS file.
|
|
96
|
+
*/
|
|
97
|
+
const is_route_resolution_request = has_resolution_prefix(url.pathname);
|
|
98
|
+
const is_data_request = has_data_suffix(url.pathname);
|
|
99
|
+
|
|
100
|
+
if (is_route_resolution_request) {
|
|
101
|
+
url.pathname = strip_resolution_prefix(url.pathname);
|
|
102
|
+
} else if (is_data_request) {
|
|
92
103
|
url.pathname =
|
|
93
104
|
strip_data_suffix(url.pathname) +
|
|
94
105
|
(url.searchParams.get(TRAILING_SLASH_PARAM) === '1' ? '/' : '') || '/';
|
|
@@ -100,19 +111,19 @@ export async function respond(request, options, manifest, state) {
|
|
|
100
111
|
url.searchParams.delete(INVALIDATED_PARAM);
|
|
101
112
|
}
|
|
102
113
|
|
|
103
|
-
|
|
104
|
-
|
|
114
|
+
let resolved_path;
|
|
115
|
+
|
|
105
116
|
try {
|
|
106
|
-
|
|
117
|
+
// reroute could alter the given URL, so we pass a copy
|
|
118
|
+
resolved_path = options.hooks.reroute({ url: new URL(url) }) ?? url.pathname;
|
|
107
119
|
} catch {
|
|
108
120
|
return text('Internal Server Error', {
|
|
109
121
|
status: 500
|
|
110
122
|
});
|
|
111
123
|
}
|
|
112
124
|
|
|
113
|
-
let decoded;
|
|
114
125
|
try {
|
|
115
|
-
|
|
126
|
+
resolved_path = decode_pathname(resolved_path);
|
|
116
127
|
} catch {
|
|
117
128
|
return text('Malformed URI', { status: 400 });
|
|
118
129
|
}
|
|
@@ -124,17 +135,21 @@ export async function respond(request, options, manifest, state) {
|
|
|
124
135
|
let params = {};
|
|
125
136
|
|
|
126
137
|
if (base && !state.prerendering?.fallback) {
|
|
127
|
-
if (!
|
|
138
|
+
if (!resolved_path.startsWith(base)) {
|
|
128
139
|
return text('Not found', { status: 404 });
|
|
129
140
|
}
|
|
130
|
-
|
|
141
|
+
resolved_path = resolved_path.slice(base.length) || '/';
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
if (is_route_resolution_request) {
|
|
145
|
+
return resolve_route(resolved_path, new URL(request.url), manifest);
|
|
131
146
|
}
|
|
132
147
|
|
|
133
|
-
if (
|
|
148
|
+
if (resolved_path === `/${app_dir}/env.js`) {
|
|
134
149
|
return get_public_env(request);
|
|
135
150
|
}
|
|
136
151
|
|
|
137
|
-
if (
|
|
152
|
+
if (resolved_path.startsWith(`/${app_dir}`)) {
|
|
138
153
|
// Ensure that 404'd static assets are not cached - some adapters might apply caching by default
|
|
139
154
|
const headers = new Headers();
|
|
140
155
|
headers.set('cache-control', 'public, max-age=0, must-revalidate');
|
|
@@ -146,7 +161,7 @@ export async function respond(request, options, manifest, state) {
|
|
|
146
161
|
const matchers = await manifest._.matchers();
|
|
147
162
|
|
|
148
163
|
for (const candidate of manifest._.routes) {
|
|
149
|
-
const match = candidate.pattern.exec(
|
|
164
|
+
const match = candidate.pattern.exec(resolved_path);
|
|
150
165
|
if (!match) continue;
|
|
151
166
|
|
|
152
167
|
const matched = exec(match, candidate.params, matchers);
|
|
@@ -186,6 +201,10 @@ export async function respond(request, options, manifest, state) {
|
|
|
186
201
|
request,
|
|
187
202
|
route: { id: route?.id ?? null },
|
|
188
203
|
setHeaders: (new_headers) => {
|
|
204
|
+
if (__SVELTEKIT_DEV__) {
|
|
205
|
+
validateHeaders(new_headers);
|
|
206
|
+
}
|
|
207
|
+
|
|
189
208
|
for (const key in new_headers) {
|
|
190
209
|
const lower = key.toLowerCase();
|
|
191
210
|
const value = new_headers[key];
|
|
@@ -508,11 +527,11 @@ export async function respond(request, options, manifest, state) {
|
|
|
508
527
|
}
|
|
509
528
|
|
|
510
529
|
if (state.error && event.isSubRequest) {
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
});
|
|
530
|
+
// avoid overwriting the headers. This could be a same origin fetch request
|
|
531
|
+
// to an external service from the root layout while rendering an error page
|
|
532
|
+
const headers = new Headers(request.headers);
|
|
533
|
+
headers.set('x-sveltekit-error', 'true');
|
|
534
|
+
return await fetch(request, { headers });
|
|
516
535
|
}
|
|
517
536
|
|
|
518
537
|
if (state.error) {
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/** @type {Set<string>} */
|
|
2
|
+
const VALID_CACHE_CONTROL_DIRECTIVES = new Set([
|
|
3
|
+
'max-age',
|
|
4
|
+
'public',
|
|
5
|
+
'private',
|
|
6
|
+
'no-cache',
|
|
7
|
+
'no-store',
|
|
8
|
+
'must-revalidate',
|
|
9
|
+
'proxy-revalidate',
|
|
10
|
+
's-maxage',
|
|
11
|
+
'immutable',
|
|
12
|
+
'stale-while-revalidate',
|
|
13
|
+
'stale-if-error',
|
|
14
|
+
'no-transform',
|
|
15
|
+
'only-if-cached',
|
|
16
|
+
'max-stale',
|
|
17
|
+
'min-fresh'
|
|
18
|
+
]);
|
|
19
|
+
|
|
20
|
+
const CONTENT_TYPE_PATTERN =
|
|
21
|
+
/^(application|audio|example|font|haptics|image|message|model|multipart|text|video|x-[a-z]+)\/[-+.\w]+$/i;
|
|
22
|
+
|
|
23
|
+
/** @type {Record<string, (value: string) => void>} */
|
|
24
|
+
const HEADER_VALIDATORS = {
|
|
25
|
+
'cache-control': (value) => {
|
|
26
|
+
const error_suffix = `(While parsing "${value}".)`;
|
|
27
|
+
const parts = value.split(',').map((part) => part.trim());
|
|
28
|
+
if (parts.some((part) => !part)) {
|
|
29
|
+
throw new Error(`\`cache-control\` header contains empty directives. ${error_suffix}`);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const directives = parts.map((part) => part.split('=')[0].toLowerCase());
|
|
33
|
+
const invalid = directives.find((directive) => !VALID_CACHE_CONTROL_DIRECTIVES.has(directive));
|
|
34
|
+
if (invalid) {
|
|
35
|
+
throw new Error(
|
|
36
|
+
`Invalid cache-control directive "${invalid}". Did you mean one of: ${[...VALID_CACHE_CONTROL_DIRECTIVES].join(', ')}? ${error_suffix}`
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
},
|
|
40
|
+
|
|
41
|
+
'content-type': (value) => {
|
|
42
|
+
const type = value.split(';')[0].trim();
|
|
43
|
+
const error_suffix = `(While parsing "${value}".)`;
|
|
44
|
+
if (!CONTENT_TYPE_PATTERN.test(type)) {
|
|
45
|
+
throw new Error(`Invalid content-type value "${type}". ${error_suffix}`);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* @param {Record<string, string>} headers
|
|
52
|
+
*/
|
|
53
|
+
export function validateHeaders(headers) {
|
|
54
|
+
for (const [key, value] of Object.entries(headers)) {
|
|
55
|
+
const validator = HEADER_VALIDATORS[key.toLowerCase()];
|
|
56
|
+
try {
|
|
57
|
+
validator?.(value);
|
|
58
|
+
} catch (error) {
|
|
59
|
+
if (error instanceof Error) {
|
|
60
|
+
console.warn(`[SvelteKit] ${error.message}`);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
package/src/runtime/utils.js
CHANGED
|
@@ -32,3 +32,24 @@ export function b64_encode(buffer) {
|
|
|
32
32
|
)
|
|
33
33
|
);
|
|
34
34
|
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Like node's path.relative, but without using node
|
|
38
|
+
* @param {string} from
|
|
39
|
+
* @param {string} to
|
|
40
|
+
*/
|
|
41
|
+
export function get_relative_path(from, to) {
|
|
42
|
+
const from_parts = from.split(/[/\\]/);
|
|
43
|
+
const to_parts = to.split(/[/\\]/);
|
|
44
|
+
from_parts.pop(); // get dirname
|
|
45
|
+
|
|
46
|
+
while (from_parts[0] === to_parts[0]) {
|
|
47
|
+
from_parts.shift();
|
|
48
|
+
to_parts.shift();
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
let i = from_parts.length;
|
|
52
|
+
while (i--) from_parts[i] = '..';
|
|
53
|
+
|
|
54
|
+
return from_parts.concat(to_parts).join('/');
|
|
55
|
+
}
|
|
@@ -11,6 +11,7 @@ declare module '__sveltekit/environment' {
|
|
|
11
11
|
declare module '__sveltekit/paths' {
|
|
12
12
|
export let base: '' | `/${string}`;
|
|
13
13
|
export let assets: '' | `https://${string}` | `http://${string}` | '/_svelte_kit_assets';
|
|
14
|
+
export let app_dir: string;
|
|
14
15
|
export let relative: boolean;
|
|
15
16
|
export function reset(): void;
|
|
16
17
|
export function override(paths: { base: string; assets: string }): void;
|
|
@@ -4,6 +4,8 @@ declare global {
|
|
|
4
4
|
const __SVELTEKIT_APP_VERSION_POLL_INTERVAL__: number;
|
|
5
5
|
const __SVELTEKIT_DEV__: boolean;
|
|
6
6
|
const __SVELTEKIT_EMBEDDED__: boolean;
|
|
7
|
+
/** True if `config.kit.router.resolution === 'client'` */
|
|
8
|
+
const __SVELTEKIT_CLIENT_ROUTING__: boolean;
|
|
7
9
|
/**
|
|
8
10
|
* This makes the use of specific features visible at both dev and build time, in such a
|
|
9
11
|
* way that we can error when they are not supported by the target platform.
|
package/src/types/internal.d.ts
CHANGED
|
@@ -68,12 +68,28 @@ export interface BuildData {
|
|
|
68
68
|
out_dir: string;
|
|
69
69
|
service_worker: string | null;
|
|
70
70
|
client: {
|
|
71
|
+
/** Path to the client entry point */
|
|
71
72
|
start: string;
|
|
73
|
+
/** Path to the generated `app.js` file that contains the client manifest. Only set in case of `bundleStrategy === 'split'` */
|
|
72
74
|
app?: string;
|
|
75
|
+
/** JS files that the client entry point relies on */
|
|
73
76
|
imports: string[];
|
|
77
|
+
/**
|
|
78
|
+
* JS files that represent the entry points of the layouts/pages.
|
|
79
|
+
* An entry is undefined if the layout/page has no component or universal file (i.e. only has a `.server.js` file).
|
|
80
|
+
* Only set in case of `router.resolution === 'server'`.
|
|
81
|
+
*/
|
|
82
|
+
nodes?: (string | undefined)[];
|
|
83
|
+
/**
|
|
84
|
+
* Contains the client route manifest in a form suitable for the server which is used for server side route resolution.
|
|
85
|
+
* Notably, it contains all routes, regardless of whether they are prerendered or not (those are missing in the optimized server route manifest).
|
|
86
|
+
* Only set in case of `router.resolution === 'server'`.
|
|
87
|
+
*/
|
|
88
|
+
routes?: SSRClientRoute[];
|
|
74
89
|
stylesheets: string[];
|
|
75
90
|
fonts: string[];
|
|
76
91
|
uses_env_dynamic_public: boolean;
|
|
92
|
+
/** Only set in case of `bundleStrategy === 'inline'` */
|
|
77
93
|
inline?: {
|
|
78
94
|
script: string;
|
|
79
95
|
style: string | undefined;
|
|
@@ -104,6 +120,17 @@ export type CSRRoute = {
|
|
|
104
120
|
leaf: [has_server_load: boolean, node_loader: CSRPageNodeLoader];
|
|
105
121
|
};
|
|
106
122
|
|
|
123
|
+
/**
|
|
124
|
+
* Definition of a client side route as transported via `_app/route/...` when using server-side route resolution.
|
|
125
|
+
*/
|
|
126
|
+
export type CSRRouteServer = {
|
|
127
|
+
id: string;
|
|
128
|
+
errors: Array<number | undefined>;
|
|
129
|
+
layouts: Array<[has_server_load: boolean, node_id: number] | undefined>;
|
|
130
|
+
leaf: [has_server_load: boolean, node_id: number];
|
|
131
|
+
nodes: Record<string, CSRPageNodeLoader>;
|
|
132
|
+
};
|
|
133
|
+
|
|
107
134
|
export interface Deferred {
|
|
108
135
|
fulfil: (value: any) => void;
|
|
109
136
|
reject: (error: Error) => void;
|
|
@@ -160,11 +187,11 @@ export interface ManifestData {
|
|
|
160
187
|
|
|
161
188
|
export interface PageNode {
|
|
162
189
|
depth: number;
|
|
163
|
-
/** The +page.svelte */
|
|
190
|
+
/** The +page/layout.svelte */
|
|
164
191
|
component?: string; // TODO supply default component if it's missing (bit of an edge case)
|
|
165
|
-
/** The +page.js/.ts */
|
|
192
|
+
/** The +page/layout.js/.ts */
|
|
166
193
|
universal?: string;
|
|
167
|
-
/** The +page.server.js/ts */
|
|
194
|
+
/** The +page/layout.server.js/ts */
|
|
168
195
|
server?: string;
|
|
169
196
|
parent_id?: string;
|
|
170
197
|
parent?: PageNode;
|
|
@@ -304,7 +331,10 @@ export interface ServerMetadataRoute {
|
|
|
304
331
|
}
|
|
305
332
|
|
|
306
333
|
export interface ServerMetadata {
|
|
307
|
-
nodes: Array<{
|
|
334
|
+
nodes: Array<{
|
|
335
|
+
/** Also `true` when using `trailingSlash`, because we need to do a server request in that case to get its value */
|
|
336
|
+
has_server_load: boolean;
|
|
337
|
+
}>;
|
|
308
338
|
routes: Map<string, ServerMetadataRoute>;
|
|
309
339
|
}
|
|
310
340
|
|
|
@@ -328,13 +358,13 @@ export type SSRComponentLoader = () => Promise<SSRComponent>;
|
|
|
328
358
|
|
|
329
359
|
export interface SSRNode {
|
|
330
360
|
component: SSRComponentLoader;
|
|
331
|
-
/** index into the `
|
|
361
|
+
/** index into the `nodes` array in the generated `client/app.js` */
|
|
332
362
|
index: number;
|
|
333
|
-
/** external JS files */
|
|
363
|
+
/** external JS files that are loaded on the client. `imports[0]` is the entry point (e.g. `client/nodes/0.js`) */
|
|
334
364
|
imports: string[];
|
|
335
|
-
/** external CSS files */
|
|
365
|
+
/** external CSS files that are loaded on the client */
|
|
336
366
|
stylesheets: string[];
|
|
337
|
-
/** external font files */
|
|
367
|
+
/** external font files that are loaded on the client */
|
|
338
368
|
fonts: string[];
|
|
339
369
|
/** inlined styles */
|
|
340
370
|
inline_styles?(): MaybePromise<Record<string, string>>;
|
|
@@ -367,7 +397,6 @@ export interface SSRNode {
|
|
|
367
397
|
export type SSRNodeLoader = () => Promise<SSRNode>;
|
|
368
398
|
|
|
369
399
|
export interface SSROptions {
|
|
370
|
-
app_dir: string;
|
|
371
400
|
app_template_contains_nonce: boolean;
|
|
372
401
|
csp: ValidatedConfig['kit']['csp'];
|
|
373
402
|
csrf_check_origin: boolean;
|
|
@@ -417,6 +446,15 @@ export interface SSRRoute {
|
|
|
417
446
|
endpoint_id?: string;
|
|
418
447
|
}
|
|
419
448
|
|
|
449
|
+
export interface SSRClientRoute {
|
|
450
|
+
id: string;
|
|
451
|
+
pattern: RegExp;
|
|
452
|
+
params: RouteParam[];
|
|
453
|
+
errors: Array<number | undefined>;
|
|
454
|
+
layouts: Array<[has_server_load: boolean, node_id: number] | undefined>;
|
|
455
|
+
leaf: [has_server_load: boolean, node_id: number];
|
|
456
|
+
}
|
|
457
|
+
|
|
420
458
|
export interface SSRState {
|
|
421
459
|
fallback?: string;
|
|
422
460
|
getClientAddress(): string;
|
package/src/utils/filesystem.js
CHANGED
|
@@ -169,11 +169,12 @@ export function from_fs(str) {
|
|
|
169
169
|
export function resolve_entry(entry) {
|
|
170
170
|
if (fs.existsSync(entry)) {
|
|
171
171
|
const stats = fs.statSync(entry);
|
|
172
|
-
const index = path.join(entry, 'index');
|
|
173
|
-
|
|
174
172
|
if (stats.isFile()) {
|
|
175
173
|
return entry;
|
|
176
|
-
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
const index = path.join(entry, 'index');
|
|
177
|
+
if (fs.existsSync(index + '.js') || fs.existsSync(index + '.ts')) {
|
|
177
178
|
return resolve_entry(index);
|
|
178
179
|
}
|
|
179
180
|
}
|
package/src/utils/routing.js
CHANGED
|
@@ -265,3 +265,11 @@ export function resolve_route(id, params) {
|
|
|
265
265
|
.join('/')
|
|
266
266
|
);
|
|
267
267
|
}
|
|
268
|
+
|
|
269
|
+
/**
|
|
270
|
+
* @param {import('types').SSRNode} node
|
|
271
|
+
* @returns {boolean}
|
|
272
|
+
*/
|
|
273
|
+
export function has_server_load(node) {
|
|
274
|
+
return node.server?.load !== undefined || node.server?.trailingSlash !== undefined;
|
|
275
|
+
}
|
package/src/utils/url.js
CHANGED
|
@@ -199,26 +199,3 @@ function allow_nodejs_console_log(url) {
|
|
|
199
199
|
};
|
|
200
200
|
}
|
|
201
201
|
}
|
|
202
|
-
|
|
203
|
-
const DATA_SUFFIX = '/__data.json';
|
|
204
|
-
const HTML_DATA_SUFFIX = '.html__data.json';
|
|
205
|
-
|
|
206
|
-
/** @param {string} pathname */
|
|
207
|
-
export function has_data_suffix(pathname) {
|
|
208
|
-
return pathname.endsWith(DATA_SUFFIX) || pathname.endsWith(HTML_DATA_SUFFIX);
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
/** @param {string} pathname */
|
|
212
|
-
export function add_data_suffix(pathname) {
|
|
213
|
-
if (pathname.endsWith('.html')) return pathname.replace(/\.html$/, HTML_DATA_SUFFIX);
|
|
214
|
-
return pathname.replace(/\/$/, '') + DATA_SUFFIX;
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
/** @param {string} pathname */
|
|
218
|
-
export function strip_data_suffix(pathname) {
|
|
219
|
-
if (pathname.endsWith(HTML_DATA_SUFFIX)) {
|
|
220
|
-
return pathname.slice(0, -HTML_DATA_SUFFIX.length) + '.html';
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
return pathname.slice(0, -DATA_SUFFIX.length);
|
|
224
|
-
}
|
package/src/version.js
CHANGED
package/types/index.d.ts
CHANGED
|
@@ -641,6 +641,28 @@ declare module '@sveltejs/kit' {
|
|
|
641
641
|
* @since 2.14.0
|
|
642
642
|
*/
|
|
643
643
|
type?: 'pathname' | 'hash';
|
|
644
|
+
/**
|
|
645
|
+
* How to determine which route to load when navigating to a new page.
|
|
646
|
+
*
|
|
647
|
+
* By default, SvelteKit will serve a route manifest to the browser.
|
|
648
|
+
* When navigating, this manifest is used (along with the `reroute` hook, if it exists) to determine which components to load and which `load` functions to run.
|
|
649
|
+
* Because everything happens on the client, this decision can be made immediately. The drawback is that the manifest needs to be
|
|
650
|
+
* loaded and parsed before the first navigation can happen, which may have an impact if your app contains many routes.
|
|
651
|
+
*
|
|
652
|
+
* Alternatively, SvelteKit can determine the route on the server. This means that for every navigation to a path that has not yet been visited, the server will be asked to determine the route.
|
|
653
|
+
* This has several advantages:
|
|
654
|
+
* - The client does not need to load the routing manifest upfront, which can lead to faster initial page loads
|
|
655
|
+
* - The list of routes is hidden from public view
|
|
656
|
+
* - The server has an opportunity to intercept each navigation (for example through a middleware), enabling (for example) A/B testing opaque to SvelteKit
|
|
657
|
+
|
|
658
|
+
* The drawback is that for unvisited paths, resolution will take slightly longer (though this is mitigated by [preloading](https://svelte.dev/docs/kit/link-options#data-sveltekit-preload-data)).
|
|
659
|
+
*
|
|
660
|
+
* > [!NOTE] When using server-side route resolution and prerendering, the resolution is prerendered along with the route itself.
|
|
661
|
+
*
|
|
662
|
+
* @default "client"
|
|
663
|
+
* @since 2.17.0
|
|
664
|
+
*/
|
|
665
|
+
resolution?: 'client' | 'server';
|
|
644
666
|
};
|
|
645
667
|
serviceWorker?: {
|
|
646
668
|
/**
|
|
@@ -1070,31 +1092,31 @@ declare module '@sveltejs/kit' {
|
|
|
1070
1092
|
}
|
|
1071
1093
|
|
|
1072
1094
|
/**
|
|
1073
|
-
* The shape of the `$page` store
|
|
1095
|
+
* The shape of the [`page`](https://svelte.dev/docs/kit/$app-state#page) reactive object and the [`$page`](https://svelte.dev/docs/kit/$app-stores) store.
|
|
1074
1096
|
*/
|
|
1075
1097
|
export interface Page<
|
|
1076
1098
|
Params extends Record<string, string> = Record<string, string>,
|
|
1077
1099
|
RouteId extends string | null = string | null
|
|
1078
1100
|
> {
|
|
1079
1101
|
/**
|
|
1080
|
-
* The URL of the current page
|
|
1102
|
+
* The URL of the current page.
|
|
1081
1103
|
*/
|
|
1082
1104
|
url: URL;
|
|
1083
1105
|
/**
|
|
1084
|
-
* The parameters of the current page - e.g. for a route like `/blog/[slug]`, a `{ slug: string }` object
|
|
1106
|
+
* The parameters of the current page - e.g. for a route like `/blog/[slug]`, a `{ slug: string }` object.
|
|
1085
1107
|
*/
|
|
1086
1108
|
params: Params;
|
|
1087
1109
|
/**
|
|
1088
|
-
* Info about the current route
|
|
1110
|
+
* Info about the current route.
|
|
1089
1111
|
*/
|
|
1090
1112
|
route: {
|
|
1091
1113
|
/**
|
|
1092
|
-
* The ID of the current route - e.g. for `src/routes/blog/[slug]`, it would be `/blog/[slug]
|
|
1114
|
+
* The ID of the current route - e.g. for `src/routes/blog/[slug]`, it would be `/blog/[slug]`.
|
|
1093
1115
|
*/
|
|
1094
1116
|
id: RouteId;
|
|
1095
1117
|
};
|
|
1096
1118
|
/**
|
|
1097
|
-
*
|
|
1119
|
+
* HTTP status code of the current page.
|
|
1098
1120
|
*/
|
|
1099
1121
|
status: number;
|
|
1100
1122
|
/**
|
|
@@ -1279,6 +1301,7 @@ declare module '@sveltejs/kit' {
|
|
|
1279
1301
|
client: NonNullable<BuildData['client']>;
|
|
1280
1302
|
nodes: SSRNodeLoader[];
|
|
1281
1303
|
routes: SSRRoute[];
|
|
1304
|
+
prerendered_routes: Set<string>;
|
|
1282
1305
|
matchers: () => Promise<Record<string, ParamMatcher>>;
|
|
1283
1306
|
/** A `[file]: size` map of all assets imported by server code */
|
|
1284
1307
|
server_assets: Record<string, number>;
|
|
@@ -1692,12 +1715,28 @@ declare module '@sveltejs/kit' {
|
|
|
1692
1715
|
out_dir: string;
|
|
1693
1716
|
service_worker: string | null;
|
|
1694
1717
|
client: {
|
|
1718
|
+
/** Path to the client entry point */
|
|
1695
1719
|
start: string;
|
|
1720
|
+
/** Path to the generated `app.js` file that contains the client manifest. Only set in case of `bundleStrategy === 'split'` */
|
|
1696
1721
|
app?: string;
|
|
1722
|
+
/** JS files that the client entry point relies on */
|
|
1697
1723
|
imports: string[];
|
|
1724
|
+
/**
|
|
1725
|
+
* JS files that represent the entry points of the layouts/pages.
|
|
1726
|
+
* An entry is undefined if the layout/page has no component or universal file (i.e. only has a `.server.js` file).
|
|
1727
|
+
* Only set in case of `router.resolution === 'server'`.
|
|
1728
|
+
*/
|
|
1729
|
+
nodes?: (string | undefined)[];
|
|
1730
|
+
/**
|
|
1731
|
+
* Contains the client route manifest in a form suitable for the server which is used for server side route resolution.
|
|
1732
|
+
* Notably, it contains all routes, regardless of whether they are prerendered or not (those are missing in the optimized server route manifest).
|
|
1733
|
+
* Only set in case of `router.resolution === 'server'`.
|
|
1734
|
+
*/
|
|
1735
|
+
routes?: SSRClientRoute[];
|
|
1698
1736
|
stylesheets: string[];
|
|
1699
1737
|
fonts: string[];
|
|
1700
1738
|
uses_env_dynamic_public: boolean;
|
|
1739
|
+
/** Only set in case of `bundleStrategy === 'inline'` */
|
|
1701
1740
|
inline?: {
|
|
1702
1741
|
script: string;
|
|
1703
1742
|
style: string | undefined;
|
|
@@ -1720,11 +1759,11 @@ declare module '@sveltejs/kit' {
|
|
|
1720
1759
|
|
|
1721
1760
|
interface PageNode {
|
|
1722
1761
|
depth: number;
|
|
1723
|
-
/** The +page.svelte */
|
|
1762
|
+
/** The +page/layout.svelte */
|
|
1724
1763
|
component?: string; // TODO supply default component if it's missing (bit of an edge case)
|
|
1725
|
-
/** The +page.js/.ts */
|
|
1764
|
+
/** The +page/layout.js/.ts */
|
|
1726
1765
|
universal?: string;
|
|
1727
|
-
/** The +page.server.js/ts */
|
|
1766
|
+
/** The +page/layout.server.js/ts */
|
|
1728
1767
|
server?: string;
|
|
1729
1768
|
parent_id?: string;
|
|
1730
1769
|
parent?: PageNode;
|
|
@@ -1796,13 +1835,13 @@ declare module '@sveltejs/kit' {
|
|
|
1796
1835
|
|
|
1797
1836
|
interface SSRNode {
|
|
1798
1837
|
component: SSRComponentLoader;
|
|
1799
|
-
/** index into the `
|
|
1838
|
+
/** index into the `nodes` array in the generated `client/app.js` */
|
|
1800
1839
|
index: number;
|
|
1801
|
-
/** external JS files */
|
|
1840
|
+
/** external JS files that are loaded on the client. `imports[0]` is the entry point (e.g. `client/nodes/0.js`) */
|
|
1802
1841
|
imports: string[];
|
|
1803
|
-
/** external CSS files */
|
|
1842
|
+
/** external CSS files that are loaded on the client */
|
|
1804
1843
|
stylesheets: string[];
|
|
1805
|
-
/** external font files */
|
|
1844
|
+
/** external font files that are loaded on the client */
|
|
1806
1845
|
fonts: string[];
|
|
1807
1846
|
/** inlined styles */
|
|
1808
1847
|
inline_styles?(): MaybePromise<Record<string, string>>;
|
|
@@ -1859,6 +1898,15 @@ declare module '@sveltejs/kit' {
|
|
|
1859
1898
|
endpoint_id?: string;
|
|
1860
1899
|
}
|
|
1861
1900
|
|
|
1901
|
+
interface SSRClientRoute {
|
|
1902
|
+
id: string;
|
|
1903
|
+
pattern: RegExp;
|
|
1904
|
+
params: RouteParam[];
|
|
1905
|
+
errors: Array<number | undefined>;
|
|
1906
|
+
layouts: Array<[has_server_load: boolean, node_id: number] | undefined>;
|
|
1907
|
+
leaf: [has_server_load: boolean, node_id: number];
|
|
1908
|
+
}
|
|
1909
|
+
|
|
1862
1910
|
type ValidatedConfig = Config & {
|
|
1863
1911
|
kit: ValidatedKitConfig;
|
|
1864
1912
|
extensions: string[];
|
|
@@ -2356,6 +2404,17 @@ declare module '$app/state' {
|
|
|
2356
2404
|
* {/if}
|
|
2357
2405
|
* ```
|
|
2358
2406
|
*
|
|
2407
|
+
* Changes to `page` are available exclusively with runes. (The legacy reactivity syntax will not reflect any changes)
|
|
2408
|
+
*
|
|
2409
|
+
* ```svelte
|
|
2410
|
+
* <!--- file: +page.svelte --->
|
|
2411
|
+
* <script>
|
|
2412
|
+
* import { page } from '$app/state';
|
|
2413
|
+
* const id = $derived(page.params.id); // This will correctly update id for usage on this page
|
|
2414
|
+
* $: badId = page.params.id; // Do not use; will never update after initial load
|
|
2415
|
+
* </script>
|
|
2416
|
+
* ```
|
|
2417
|
+
*
|
|
2359
2418
|
* On the server, values can only be read during rendering (in other words _not_ in e.g. `load` functions). In the browser, the values can be read at any time.
|
|
2360
2419
|
*
|
|
2361
2420
|
* */
|
package/types/index.d.ts.map
CHANGED
|
@@ -79,6 +79,7 @@
|
|
|
79
79
|
"PrerenderEntryGenerator",
|
|
80
80
|
"SSREndpoint",
|
|
81
81
|
"SSRRoute",
|
|
82
|
+
"SSRClientRoute",
|
|
82
83
|
"ValidatedConfig",
|
|
83
84
|
"ValidatedKitConfig",
|
|
84
85
|
"isHttpError",
|
|
@@ -159,6 +160,6 @@
|
|
|
159
160
|
null,
|
|
160
161
|
null
|
|
161
162
|
],
|
|
162
|
-
"mappings": ";;;;;;;;;kBA2BiBA,OAAOA;;;;;;;;;;;;;;;;;;;;;;;;;;;aA2BZC,cAAcA;;;;;;aAMdC,cAAcA;;;;;;;;;;;;;;;kBAeTC,aAAaA;;;;;;;;;;;;;;;;;kBAiBbC,OAAOA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBAkGPC,MAAMA;;;;;;;;;;;;;;;;;;;;;kBAqBNC,OAAOA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBA4DPC,QAAQA;;;;;;;;kBAQRC,SAASA
|
|
163
|
+
"mappings": ";;;;;;;;;kBA2BiBA,OAAOA;;;;;;;;;;;;;;;;;;;;;;;;;;;aA2BZC,cAAcA;;;;;;aAMdC,cAAcA;;;;;;;;;;;;;;;kBAeTC,aAAaA;;;;;;;;;;;;;;;;;kBAiBbC,OAAOA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBAkGPC,MAAMA;;;;;;;;;;;;;;;;;;;;;kBAqBNC,OAAOA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBA4DPC,QAAQA;;;;;;;;kBAQRC,SAASA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;aAiedC,MAAMA;;;;;;;;;;;aAWNC,iBAAiBA;;;;;;;;;;;;;aAajBC,iBAAiBA;;;;;;;;;;aAUjBC,WAAWA;;;;;;;;;;aAUXC,UAAUA;;;;;;aAMVC,UAAUA;;;;;;aAMVC,OAAOA;;;;;;;;;;;;;;;;;;;;;;;;;;aA0BPC,SAASA;;;;;kBAKJC,WAAWA;;;;;;;;;;;;aAYhBC,IAAIA;;;;;;;;;;;;kBAYCC,SAASA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBA4GTC,eAAeA;;;;;;;;;;;;;;;;;;;;;;;;;;kBA0BfC,gBAAgBA;;;;;;;;;;;;;;;;;;;;;;;;aAwBrBC,cAAcA;;kBAETC,UAAUA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBAoCVC,cAAcA;;;;;;;;;;kBAUdC,UAAUA;;;;;;;;;;;;;;;;;;kBAkBVC,aAAaA;;;;;;;;;;;;;;;;;;;kBAmBbC,IAAIA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;aA8CTC,YAAYA;;kBAEPC,YAAYA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;aA4FjBC,cAAcA;;;;;kBAKTC,cAAcA;;;;;;;;;;;;;;;;;;;;;;;kBAuBdC,eAAeA;;;;;;;;;;;;;;;cAenBC,MAAMA;;;;;;kBAMFC,iBAAiBA;;;;;;;kBAOjBC,WAAWA;;;;;;;;;;;;;;;;;;;;;;aAsBhBC,UAAUA;;;;;;;kBAOLC,eAAeA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;aAqEpBC,MAAMA;;;;;;;;;;aAUNC,OAAOA;;;;;;;;;;;;;;;;aAgBPC,YAAYA;;;;;;;;;;;;kBC15CXC,SAASA;;;;;;;;;;kBAqBTC,QAAQA;;;;;;;aDk6CTC,cAAcA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBA6BTC,QAAQA;;;;WE98CRC,YAAYA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;WAkDZC,GAAGA;;;;;;;;;;;;;;;;;;;;;WAqBHC,aAAaA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;MAmElBC,UAAUA;;WAELC,MAAMA;;;;;;;;;MASXC,YAAYA;;WAEPC,WAAWA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;WAmCXC,yBAAyBA;;;;;;;;;;WAUzBC,yBAAyBA;;;;WAIzBC,sCAAsCA;;;;MAI3CC,8BAA8BA;MAC9BC,8BAA8BA;MAC9BC,2CAA2CA;;;;;;aAM3CC,eAAeA;;WAIVC,cAAcA;;;;;WAKdC,YAAYA;;;;;;MAMjBC,aAAaA;WCxLRC,KAAKA;;;;;;WAcLC,SAASA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;WAgHTC,YAAYA;;;;;;;;;;;;WAYZC,QAAQA;;;;;;;;;;;;;;MAyBbC,iBAAiBA;;;;;;;;WAUZC,UAAUA;;;;;;;;;;;;;WAaVC,SAASA;;;;;;;;;;;;;;;;;;;;;;;WAyGTC,YAAYA;;;;;;;;;;;;;;;;MAgBjBC,kBAAkBA;;WAEbC,OAAOA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;MAsCZC,aAAaA;;WA2BRC,eAAeA;;;;;;MAMpBC,uBAAuBA;;MAEvBC,WAAWA;;;;;;;;WAQNC,QAAQA;;;;;;;;;WASRC,cAAcA;;;;;;;;;MA2CnBC,eAAeA;;;;;MAKfC,kBAAkBA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBCladC,WAAWA;;;;;;;;;;;;;;;;;;;iBAsBXC,QAAQA;;;;;iBAiBRC,UAAUA;;;;;;iBASVC,IAAIA;;;;;;iBA8BJC,IAAIA;;;;;;;;;;;;;;;;iBAkDJC,eAAeA;;;cC3MlBC,OAAOA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBCoEJC,QAAQA;;;;;;iBCoCFC,UAAUA;;;;;;iBAkCVC,WAAWA;;;;;iBAgFjBC,oBAAoBA;;;;;;;;;;;iBC3MpBC,gBAAgBA;;;;;;;;;iBCgHVC,SAASA;;;;;;;;;cC/HlBC,OAAOA;;;;;cAKPC,GAAGA;;;;;cAKHC,QAAQA;;;;;cAKRC,OAAOA;;;;;;;;;;;;;;;;;;;;;;;;iBCWJC,WAAWA;;;;;;;;;;;;;;;;;;;;;;;;iBA8CXC,OAAOA;;;;;;;iBC2+DDC,WAAWA;;;;;;;;;;;iBA/TjBC,aAAaA;;;;;;;;;;;;iBAiBbC,cAAcA;;;;;;;;;;iBAedC,UAAUA;;;;;iBASVC,qBAAqBA;;;;;;;;;;iBA8BrBC,IAAIA;;;;;;;;;;;;;;;;;;;;;;;;;iBAsCJC,UAAUA;;;;iBA0BVC,aAAaA;;;;;;;;;;;;iBAqBPC,WAAWA;;;;;;;;;;;;;;;;;;iBAoCXC,WAAWA;;;;;iBAsCjBC,SAASA;;;;;iBA+CTC,YAAYA;MVj3DhB5D,YAAYA;;;;;;;;;;;YWtJb6D,IAAIA;;;;;;;YAOJC,MAAMA;;;;;;;;;;;;;;;;;iBAiBDC,YAAYA;;;;;;;;;;;;;;;;;;iBCVZC,IAAIA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cC8BPC,IAAIA;;;;;cAQJC,UAAUA;;;;;;;;;;;cAMVC,OAAOA;;;;;;;;;iBCrDPC,SAASA;;;;;;;;;;;;;;;cAyBTH,IAAIA;;;;;;;;;;cAiBJC,UAAUA;;;;;;;;cAeVC,OAAOA",
|
|
163
164
|
"ignoreList": []
|
|
164
165
|
}
|