@sveltejs/kit 3.0.0-next.12 → 3.0.0-next.14
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 +11 -11
- package/src/cli.js +2 -2
- package/src/core/adapt/builder.js +8 -5
- package/src/core/generate_manifest/index.js +6 -0
- package/src/core/postbuild/entities.js +8 -2
- package/src/core/postbuild/fallback.js +2 -1
- package/src/core/postbuild/prerender.js +15 -6
- package/src/core/sync/create_manifest_data/conflict.js +1 -1
- package/src/core/sync/create_manifest_data/index.js +33 -2
- package/src/core/sync/write_app_types.js +73 -29
- package/src/core/sync/write_tsconfig/index.js +15 -2
- package/src/core/sync/write_types/index.js +5 -2
- package/src/exports/index.js +23 -12
- package/src/exports/internal/shared.js +4 -12
- package/src/exports/node/index.js +2 -7
- package/src/exports/public.d.ts +61 -12
- package/src/exports/vite/build/remote.js +10 -12
- package/src/exports/vite/dev/index.js +32 -19
- package/src/exports/vite/index.js +162 -133
- package/src/exports/vite/utils.js +1 -7
- package/src/runtime/app/server/remote/form.js +9 -1
- package/src/runtime/app/server/remote/prerender.js +13 -9
- package/src/runtime/app/server/remote/query.js +0 -6
- package/src/runtime/app/server/remote/requested.js +4 -4
- package/src/runtime/app/state/client.js +3 -0
- package/src/runtime/app/state/index.js +2 -2
- package/src/runtime/app/state/server.js +3 -0
- package/src/runtime/client/client.js +731 -342
- package/src/runtime/client/constants.js +2 -6
- package/src/runtime/client/fetcher.js +24 -25
- package/src/runtime/client/remote-functions/form.svelte.js +42 -14
- package/src/runtime/client/remote-functions/prerender.svelte.js +2 -2
- package/src/runtime/client/remote-functions/query/index.js +1 -1
- package/src/runtime/client/remote-functions/query/instance.svelte.js +2 -2
- package/src/runtime/client/remote-functions/query-batch.svelte.js +2 -2
- package/src/runtime/client/remote-functions/query-live/instance.svelte.js +2 -2
- package/src/runtime/client/remote-functions/query-live/iterator.js +10 -8
- package/src/runtime/client/remote-functions/query-live/proxy.js +0 -10
- package/src/runtime/client/remote-functions/shared.svelte.js +12 -11
- package/src/runtime/client/state.svelte.js +10 -22
- package/src/runtime/client/types.d.ts +1 -2
- package/src/runtime/client/utils.js +22 -14
- package/src/runtime/components/root.svelte +4 -14
- package/src/runtime/form-utils.js +4 -6
- package/src/runtime/pathname.js +37 -0
- package/src/runtime/props.svelte.js +71 -0
- package/src/runtime/server/fetch.js +9 -14
- package/src/runtime/server/index.js +10 -24
- package/src/runtime/server/page/crypto.js +2 -2
- package/src/runtime/server/page/csp.js +88 -104
- package/src/runtime/server/page/index.js +1 -2
- package/src/runtime/server/page/load_data.js +16 -33
- package/src/runtime/server/page/render.js +46 -25
- package/src/runtime/server/page/respond_with_error.js +1 -3
- package/src/runtime/server/page/serialize_data.js +2 -13
- package/src/runtime/server/page/server_routing.js +58 -9
- package/src/runtime/server/respond.js +20 -29
- package/src/runtime/server/state.js +43 -0
- package/src/runtime/shared.js +4 -2
- package/src/runtime/utils.js +3 -0
- package/src/types/ambient-private.d.ts +2 -2
- package/src/types/ambient.d.ts +59 -8
- package/src/types/global-private.d.ts +1 -1
- package/src/types/internal.d.ts +4 -8
- package/src/types/private.d.ts +3 -12
- package/src/utils/hash.js +21 -0
- package/src/utils/http.js +8 -7
- package/src/utils/import.js +2 -1
- package/src/utils/params.js +1 -1
- package/src/utils/regex.js +9 -0
- package/src/utils/routing.js +52 -27
- package/src/utils/url.js +1 -0
- package/src/version.js +1 -1
- package/types/index.d.ts +165 -66
- package/types/index.d.ts.map +2 -1
- package/src/exports/node/polyfills.js +0 -30
- package/src/runtime/types.d.ts +0 -8
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/** @import {
|
|
1
|
+
/** @import { Component } from 'svelte'; */
|
|
2
2
|
import * as devalue from 'devalue';
|
|
3
3
|
import { DEV } from 'esm-env';
|
|
4
4
|
import { isRedirect, text } from '@sveltejs/kit';
|
|
@@ -11,7 +11,11 @@ import { uneval_action_response } from './actions.js';
|
|
|
11
11
|
import { SVELTE_KIT_ASSETS } from '../../../constants.js';
|
|
12
12
|
import { SCHEME } from '../../../utils/url.js';
|
|
13
13
|
import { create_server_routing_response, generate_route_object } from './server_routing.js';
|
|
14
|
-
import {
|
|
14
|
+
import {
|
|
15
|
+
add_data_suffix,
|
|
16
|
+
add_resolution_suffix,
|
|
17
|
+
route_id_resolution_pathname
|
|
18
|
+
} from '../../pathname.js';
|
|
15
19
|
import { try_get_request_store, with_request_store } from '@sveltejs/kit/internal/server';
|
|
16
20
|
import { text_encoder } from '../../utils.js';
|
|
17
21
|
import { count_non_ssi_comments, create_replacer, get_global_name } from '../utils.js';
|
|
@@ -20,6 +24,7 @@ import * as env from '__sveltekit/env';
|
|
|
20
24
|
import { collect_remote_data } from '../remote-functions.js';
|
|
21
25
|
import Root from '../../components/root.svelte';
|
|
22
26
|
import { render } from 'svelte/server';
|
|
27
|
+
import { Props, RenderNode } from '../../props.svelte.js';
|
|
23
28
|
|
|
24
29
|
// TODO rename this function/module
|
|
25
30
|
|
|
@@ -134,25 +139,29 @@ export async function render_response({
|
|
|
134
139
|
}
|
|
135
140
|
|
|
136
141
|
if (page_config.ssr) {
|
|
137
|
-
|
|
138
|
-
const props = {
|
|
139
|
-
components: [],
|
|
140
|
-
resetters: [],
|
|
141
|
-
form: form_value,
|
|
142
|
-
tree: /** @type {RenderNode} */ ({}),
|
|
142
|
+
const page = {
|
|
143
143
|
error,
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
state: {}
|
|
153
|
-
}
|
|
144
|
+
params: /** @type {Record<string, any>} */ (event.params),
|
|
145
|
+
route: event.route,
|
|
146
|
+
status,
|
|
147
|
+
url: event.url,
|
|
148
|
+
data: {},
|
|
149
|
+
form: form_value,
|
|
150
|
+
shallow: null,
|
|
151
|
+
state: {}
|
|
154
152
|
};
|
|
155
153
|
|
|
154
|
+
const props = new Props({
|
|
155
|
+
page,
|
|
156
|
+
tree: new RenderNode(
|
|
157
|
+
// TODO tidy up
|
|
158
|
+
/** @type {Component} */ (await branch[0].node.component?.()),
|
|
159
|
+
/** @type {Component} */ (error_components?.[1])
|
|
160
|
+
),
|
|
161
|
+
form: form_value,
|
|
162
|
+
error: error ?? undefined
|
|
163
|
+
});
|
|
164
|
+
|
|
156
165
|
let current_node = props.tree;
|
|
157
166
|
let data = props.page.data;
|
|
158
167
|
|
|
@@ -161,16 +170,14 @@ export async function render_response({
|
|
|
161
170
|
|
|
162
171
|
data = { ...data, ...node.data };
|
|
163
172
|
|
|
164
|
-
// TODO this is undefined sometimes... where does the default error component come from?
|
|
165
|
-
const error = error_components?.slice(0, i + 1).findLast((x) => x);
|
|
166
|
-
|
|
167
|
-
current_node.error = error;
|
|
168
|
-
current_node.component = await node.node.component?.();
|
|
169
173
|
current_node.data = data;
|
|
170
174
|
|
|
171
175
|
if (i < branch.length - 1) {
|
|
172
|
-
current_node.child =
|
|
173
|
-
|
|
176
|
+
current_node = current_node.child = new RenderNode(
|
|
177
|
+
// TODO tidy up
|
|
178
|
+
/** @type {Component} */ (await branch[i + 1].node.component?.()),
|
|
179
|
+
/** @type {Component} */ (error_components?.slice(0, i + 2).findLast((x) => x))
|
|
180
|
+
);
|
|
174
181
|
}
|
|
175
182
|
}
|
|
176
183
|
|
|
@@ -387,6 +394,20 @@ export async function render_response({
|
|
|
387
394
|
pathname,
|
|
388
395
|
create_server_routing_response(route, event.params, new URL(pathname, event.url), client)
|
|
389
396
|
);
|
|
397
|
+
|
|
398
|
+
// Prerender a route-ID-keyed `/_app/routes/<id>/__route.js` module alongside the
|
|
399
|
+
// pathname-keyed one above, so that `preloadCode(id)` can resolve a route ID without
|
|
400
|
+
// hitting the server.
|
|
401
|
+
if (route && !state.prerendering.resolved_route_ids.has(route.id)) {
|
|
402
|
+
state.prerendering.resolved_route_ids.add(route.id);
|
|
403
|
+
|
|
404
|
+
const id_pathname = paths.base + route_id_resolution_pathname(paths.app_dir, route.id);
|
|
405
|
+
|
|
406
|
+
state.prerendering.dependencies.set(
|
|
407
|
+
id_pathname,
|
|
408
|
+
create_server_routing_response(route, null, new URL(id_pathname, event.url), client)
|
|
409
|
+
);
|
|
410
|
+
}
|
|
390
411
|
}
|
|
391
412
|
|
|
392
413
|
const blocks = [];
|
|
@@ -17,7 +17,6 @@ import { server_data_serializer } from './data_serializer.js';
|
|
|
17
17
|
* options: import('types').SSROptions;
|
|
18
18
|
* manifest: import('@sveltejs/kit').SSRManifest;
|
|
19
19
|
* state: import('types').SSRState;
|
|
20
|
-
* status: number;
|
|
21
20
|
* error: unknown;
|
|
22
21
|
* resolve_opts: import('types').RequiredResolveOptions;
|
|
23
22
|
* }} opts
|
|
@@ -28,14 +27,13 @@ export async function respond_with_error({
|
|
|
28
27
|
options,
|
|
29
28
|
manifest,
|
|
30
29
|
state,
|
|
31
|
-
status,
|
|
32
30
|
error,
|
|
33
31
|
resolve_opts
|
|
34
32
|
}) {
|
|
35
33
|
// reroute to the fallback page to prevent an infinite chain of requests.
|
|
36
34
|
if (event.request.headers.get('x-sveltekit-error')) {
|
|
37
35
|
const transformed = await handle_error_and_jsonify(event, event_state, options, error);
|
|
38
|
-
return static_error_page(options, status, transformed.message);
|
|
36
|
+
return static_error_page(options, transformed.status, transformed.message);
|
|
39
37
|
}
|
|
40
38
|
|
|
41
39
|
/** @type {import('./types.js').Fetched[]} */
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { escape_html } from '../../../utils/escape.js';
|
|
2
|
-
import {
|
|
2
|
+
import { hash_request } from '../../../utils/hash.js';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* Inside a script element, only `</script` and `<!--` hold special meaning to the HTML parser.
|
|
@@ -78,18 +78,7 @@ export function serialize_data(fetched, filter, prerendering = false) {
|
|
|
78
78
|
}
|
|
79
79
|
|
|
80
80
|
if (fetched.request_headers || fetched.request_body) {
|
|
81
|
-
|
|
82
|
-
const values = [];
|
|
83
|
-
|
|
84
|
-
if (fetched.request_headers) {
|
|
85
|
-
values.push([...new Headers(fetched.request_headers)].join(','));
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
if (fetched.request_body) {
|
|
89
|
-
values.push(fetched.request_body);
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
attrs.push(`data-hash="${hash(...values)}"`);
|
|
81
|
+
attrs.push(`data-hash="${hash_request(fetched.request_headers, fetched.request_body)}"`);
|
|
93
82
|
}
|
|
94
83
|
|
|
95
84
|
// Compute the time the response should be cached, taking into account max-age and age.
|
|
@@ -84,26 +84,75 @@ export async function resolve_route(resolved_path, url, manifest) {
|
|
|
84
84
|
}
|
|
85
85
|
}
|
|
86
86
|
|
|
87
|
+
/**
|
|
88
|
+
* Resolve a route-ID resolution request (`/_app/routes/<id>/__route.js`) to a
|
|
89
|
+
* JS module containing the route's node loaders. Params are always `{}` since
|
|
90
|
+
* this endpoint exists to support `preloadCode(routeId)`, which doesn't need them.
|
|
91
|
+
*
|
|
92
|
+
* The module has one of three shapes, which the client uses to tell three cases apart:
|
|
93
|
+
*
|
|
94
|
+
* - `export const route = {...}` — a page route, with loaders to import
|
|
95
|
+
* - `export const endpoint_only = true` — a real route with no `+page`, so there is
|
|
96
|
+
* nothing to preload, but the client can cache that fact and stop asking
|
|
97
|
+
* - an empty module — no such route
|
|
98
|
+
*
|
|
99
|
+
* @param {string} route_id
|
|
100
|
+
* @param {URL} url
|
|
101
|
+
* @param {SSRManifest} manifest
|
|
102
|
+
* @returns {Response}
|
|
103
|
+
*/
|
|
104
|
+
export function resolve_route_by_id(route_id, url, manifest) {
|
|
105
|
+
if (!manifest._.client?.routes) {
|
|
106
|
+
return text('Server-side route resolution disabled', { status: 400 });
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
try {
|
|
110
|
+
const route = manifest._.client.routes.find((r) => r.id === route_id);
|
|
111
|
+
|
|
112
|
+
if (route) {
|
|
113
|
+
return create_server_routing_response(route, null, url, manifest._.client).response;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// `client.routes` only contains routes with a `+page`, so a miss above doesn't mean the
|
|
117
|
+
// route doesn't exist — it might be a `+server.js`-only route. `_.routes` includes those
|
|
118
|
+
// (with `page: null`), so we can distinguish "exists but has no code" from "unknown".
|
|
119
|
+
if (manifest._.routes.some((r) => r.id === route_id && !r.page)) {
|
|
120
|
+
return text('export const endpoint_only = true;', { headers: js_headers() });
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
return create_server_routing_response(null, null, url, manifest._.client).response;
|
|
124
|
+
} catch {
|
|
125
|
+
return text('Error resolving route', { status: 500 });
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
function js_headers() {
|
|
130
|
+
return new Headers({
|
|
131
|
+
'content-type': 'application/javascript; charset=utf-8'
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
|
|
87
135
|
/**
|
|
88
136
|
* @param {import('types').SSRClientRoute | null} route
|
|
89
|
-
* @param {Partial<Record<string, string>>} params
|
|
137
|
+
* @param {Partial<Record<string, string>> | null} params
|
|
90
138
|
* @param {URL} url
|
|
91
139
|
* @param {NonNullable<SSRManifest['_']['client']>} client
|
|
92
140
|
* @returns {{response: Response, body: string}}
|
|
93
141
|
*/
|
|
94
142
|
export function create_server_routing_response(route, params, url, client) {
|
|
95
|
-
const headers =
|
|
96
|
-
|
|
97
|
-
});
|
|
143
|
+
const headers = js_headers();
|
|
144
|
+
let body = '';
|
|
98
145
|
|
|
99
146
|
if (route) {
|
|
100
147
|
const csr_route = generate_route_object(route, url, client);
|
|
101
|
-
|
|
148
|
+
body = `${create_css_import(route, url, client)}export const route = ${csr_route};`;
|
|
102
149
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
150
|
+
if (params !== null) {
|
|
151
|
+
body += `\nexport const params = ${JSON.stringify(params)}`;
|
|
152
|
+
}
|
|
106
153
|
}
|
|
154
|
+
|
|
155
|
+
return { response: text(body, { headers }), body };
|
|
107
156
|
}
|
|
108
157
|
|
|
109
158
|
/**
|
|
@@ -132,5 +181,5 @@ function create_css_import(route, url, client) {
|
|
|
132
181
|
|
|
133
182
|
if (!css) return '';
|
|
134
183
|
|
|
135
|
-
return `${create_client_import(client.start, url)}.then(x => x.load_css([${css}]))
|
|
184
|
+
return `${create_client_import(client.start, url)}.then(x => x.load_css([${css}]));\n`;
|
|
136
185
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/** @import {
|
|
1
|
+
/** @import { SSRNode } from 'types' */
|
|
2
2
|
import { DEV } from 'esm-env';
|
|
3
3
|
import { json, text } from '@sveltejs/kit';
|
|
4
4
|
import { Redirect, SvelteKitError } from '@sveltejs/kit/internal';
|
|
@@ -26,13 +26,15 @@ import { validate_server_exports } from '../../utils/exports.js';
|
|
|
26
26
|
import { action_json_redirect, is_action_json_request } from './page/actions.js';
|
|
27
27
|
import { INVALIDATED_PARAM, TRAILING_SLASH_PARAM } from '../shared.js';
|
|
28
28
|
import { get_public_env } from './env_module.js';
|
|
29
|
-
import { resolve_route } from './page/server_routing.js';
|
|
29
|
+
import { resolve_route, resolve_route_by_id } from './page/server_routing.js';
|
|
30
30
|
import { validateHeaders } from './validate-headers.js';
|
|
31
31
|
import {
|
|
32
32
|
add_data_suffix,
|
|
33
33
|
add_resolution_suffix,
|
|
34
|
+
extract_route_id,
|
|
34
35
|
has_data_suffix,
|
|
35
36
|
has_resolution_suffix,
|
|
37
|
+
is_route_id_resolution_path,
|
|
36
38
|
strip_data_suffix,
|
|
37
39
|
strip_resolution_suffix
|
|
38
40
|
} from '../pathname.js';
|
|
@@ -40,6 +42,7 @@ import { server_data_serializer } from './page/data_serializer.js';
|
|
|
40
42
|
import { get_remote_id, handle_remote_call } from './remote-functions.js';
|
|
41
43
|
import { record_span } from '../telemetry/record_span.js';
|
|
42
44
|
import { otel } from '../telemetry/otel.js';
|
|
45
|
+
import { create_request_state } from './state.js';
|
|
43
46
|
|
|
44
47
|
/** @type {import('types').RequiredResolveOptions['transformPageChunk']} */
|
|
45
48
|
const default_transform = ({ html }) => html;
|
|
@@ -138,12 +141,16 @@ export async function internal_respond(request, options, manifest, state) {
|
|
|
138
141
|
|
|
139
142
|
let skip_route_resolution = false;
|
|
140
143
|
|
|
144
|
+
/** Whether this is a `/${app_dir}/routes/<route_id>/__route.js` request, used by `preloadCode` */
|
|
145
|
+
let is_route_id_resolution_request = false;
|
|
146
|
+
|
|
141
147
|
if (is_route_resolution_request) {
|
|
142
148
|
/**
|
|
143
149
|
* If the request is for a route resolution, first modify the URL, then continue as normal
|
|
144
150
|
* for path resolution, then return the route object as a JS file.
|
|
145
151
|
*/
|
|
146
152
|
url.pathname = strip_resolution_suffix(url.pathname);
|
|
153
|
+
is_route_id_resolution_request = is_route_id_resolution_path(url.pathname, base, app_dir);
|
|
147
154
|
} else if (is_data_request) {
|
|
148
155
|
url.pathname =
|
|
149
156
|
strip_data_suffix(url.pathname) +
|
|
@@ -174,30 +181,7 @@ export async function internal_respond(request, options, manifest, state) {
|
|
|
174
181
|
url
|
|
175
182
|
);
|
|
176
183
|
|
|
177
|
-
|
|
178
|
-
const event_state = {
|
|
179
|
-
prerendering: state.prerendering,
|
|
180
|
-
transport: options.hooks.transport,
|
|
181
|
-
handleValidationError: options.hooks.handleValidationError,
|
|
182
|
-
tracing: {
|
|
183
|
-
record_span
|
|
184
|
-
},
|
|
185
|
-
remote: {
|
|
186
|
-
data: null,
|
|
187
|
-
explicit: null,
|
|
188
|
-
implicit: null,
|
|
189
|
-
forms: null,
|
|
190
|
-
requested: null,
|
|
191
|
-
batches: null,
|
|
192
|
-
live_iterators: null
|
|
193
|
-
},
|
|
194
|
-
is_in_remote_function: false,
|
|
195
|
-
is_in_remote_form_or_command: false,
|
|
196
|
-
is_in_remote_query: false,
|
|
197
|
-
is_in_remote_prerender: false,
|
|
198
|
-
is_in_render: false,
|
|
199
|
-
is_in_universal_load: false
|
|
200
|
-
};
|
|
184
|
+
const event_state = create_request_state(state, options.hooks);
|
|
201
185
|
|
|
202
186
|
/** @type {import('@sveltejs/kit').RequestEvent} */
|
|
203
187
|
const event = {
|
|
@@ -270,7 +254,8 @@ export async function internal_respond(request, options, manifest, state) {
|
|
|
270
254
|
/** @type {string | null} */
|
|
271
255
|
let resolved_path = url.pathname;
|
|
272
256
|
|
|
273
|
-
|
|
257
|
+
// `reroute` hooks receive pathnames, so they must not run for route-ID resolution requests
|
|
258
|
+
if (!remote_id && !is_route_id_resolution_request) {
|
|
274
259
|
const prerendering_reroute_state = state.prerendering?.inside_reroute;
|
|
275
260
|
try {
|
|
276
261
|
// For the duration or a reroute, disable the prerendering state as reroute could call API endpoints
|
|
@@ -354,6 +339,14 @@ export async function internal_respond(request, options, manifest, state) {
|
|
|
354
339
|
}
|
|
355
340
|
|
|
356
341
|
if (is_route_resolution_request) {
|
|
342
|
+
if (is_route_id_resolution_request) {
|
|
343
|
+
return resolve_route_by_id(
|
|
344
|
+
extract_route_id(resolved_path, app_dir),
|
|
345
|
+
new URL(request.url),
|
|
346
|
+
manifest
|
|
347
|
+
);
|
|
348
|
+
}
|
|
349
|
+
|
|
357
350
|
return resolve_route(resolved_path, new URL(request.url), manifest);
|
|
358
351
|
}
|
|
359
352
|
|
|
@@ -604,7 +597,6 @@ export async function internal_respond(request, options, manifest, state) {
|
|
|
604
597
|
options,
|
|
605
598
|
manifest,
|
|
606
599
|
state,
|
|
607
|
-
status: 400,
|
|
608
600
|
error: new SvelteKitError(
|
|
609
601
|
400,
|
|
610
602
|
'Malformed URI',
|
|
@@ -781,7 +773,6 @@ export async function internal_respond(request, options, manifest, state) {
|
|
|
781
773
|
options,
|
|
782
774
|
manifest,
|
|
783
775
|
state,
|
|
784
|
-
status: 404,
|
|
785
776
|
error: new SvelteKitError(404, 'Not Found', `Not found: ${event.url.pathname}`),
|
|
786
777
|
resolve_opts
|
|
787
778
|
});
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/** @import { RequestState, ServerHooks, SSRState } from 'types' */
|
|
2
|
+
import { record_span } from '../telemetry/record_span.js';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* @param {SSRState} state
|
|
6
|
+
* @param {ServerHooks} hooks
|
|
7
|
+
* @returns {RequestState}
|
|
8
|
+
*/
|
|
9
|
+
export function create_request_state(state, hooks) {
|
|
10
|
+
// Request state is rebuilt fresh, resetting remote caches and context flags.
|
|
11
|
+
return {
|
|
12
|
+
prerendering: state.prerendering,
|
|
13
|
+
transport: hooks.transport,
|
|
14
|
+
handleValidationError: hooks.handleValidationError,
|
|
15
|
+
tracing: {
|
|
16
|
+
record_span
|
|
17
|
+
},
|
|
18
|
+
remote: {
|
|
19
|
+
data: null,
|
|
20
|
+
explicit: null,
|
|
21
|
+
implicit: null,
|
|
22
|
+
forms: null,
|
|
23
|
+
requested: null,
|
|
24
|
+
batches: null,
|
|
25
|
+
live_iterators: null
|
|
26
|
+
},
|
|
27
|
+
is_in_remote_function: false,
|
|
28
|
+
is_in_remote_form_or_command: false,
|
|
29
|
+
is_in_remote_query: false,
|
|
30
|
+
is_in_remote_prerender: false,
|
|
31
|
+
is_in_render: false,
|
|
32
|
+
is_in_universal_load: false
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* @param {SSRState} state
|
|
38
|
+
* @returns {SSRState}
|
|
39
|
+
*/
|
|
40
|
+
export function fork_state_for_subrequest(state) {
|
|
41
|
+
// Sub-requests inherit all server state except for the incremented depth.
|
|
42
|
+
return { ...state, depth: state.depth + 1 };
|
|
43
|
+
}
|
package/src/runtime/shared.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/** @import { Transport } from '@sveltejs/kit' */
|
|
2
2
|
import * as devalue from 'devalue';
|
|
3
|
-
import { base64_decode, base64_encode, text_encoder } from './utils.js';
|
|
3
|
+
import { base64_decode, base64_encode, text_decoder, text_encoder } from './utils.js';
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* @param {string} route_id
|
|
@@ -331,6 +331,7 @@ export async function stringify_command_arg(value, transport) {
|
|
|
331
331
|
*/
|
|
332
332
|
function url_friendly_base64_encode(string) {
|
|
333
333
|
const bytes = text_encoder.encode(string);
|
|
334
|
+
// TODO replace with `bytes.toBase64({ alphabet: 'base64url', omitPadding: true })` when we require Node >= 25
|
|
334
335
|
return base64_encode(bytes).replaceAll('=', '').replaceAll('+', '-').replaceAll('/', '_');
|
|
335
336
|
}
|
|
336
337
|
|
|
@@ -342,7 +343,8 @@ function url_friendly_base64_encode(string) {
|
|
|
342
343
|
export function parse_remote_arg(string, transport) {
|
|
343
344
|
if (!string) return undefined;
|
|
344
345
|
|
|
345
|
-
const json_string =
|
|
346
|
+
const json_string = text_decoder.decode(
|
|
347
|
+
// TODO replace with `Uint8Array.fromBase64(string, { alphabet: 'base64url' })` when we require Node >= 25
|
|
346
348
|
// no need to add back `=` characters, atob can handle it
|
|
347
349
|
base64_decode(string.replaceAll('-', '+').replaceAll('_', '/'))
|
|
348
350
|
);
|
package/src/runtime/utils.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { BROWSER } from 'esm-env';
|
|
2
2
|
|
|
3
3
|
export const text_encoder = new TextEncoder();
|
|
4
|
+
export const text_decoder = new TextDecoder();
|
|
4
5
|
|
|
5
6
|
/**
|
|
6
7
|
* Like node's path.relative, but without using node
|
|
@@ -28,6 +29,7 @@ export function get_relative_path(from, to) {
|
|
|
28
29
|
* @returns {string}
|
|
29
30
|
*/
|
|
30
31
|
export function base64_encode(bytes) {
|
|
32
|
+
// TODO replace with `bytes.toBase64()` when we require Node >= 25
|
|
31
33
|
// Using `Buffer` is faster than iterating
|
|
32
34
|
if (!BROWSER && globalThis.Buffer) {
|
|
33
35
|
return globalThis.Buffer.from(bytes).toString('base64');
|
|
@@ -47,6 +49,7 @@ export function base64_encode(bytes) {
|
|
|
47
49
|
* @returns {Uint8Array}
|
|
48
50
|
*/
|
|
49
51
|
export function base64_decode(encoded) {
|
|
52
|
+
// TODO replace with `Uint8Array.fromBase64(encoded)` when we require Node >= 25
|
|
50
53
|
// Using `Buffer` is faster than iterating
|
|
51
54
|
if (!BROWSER && globalThis.Buffer) {
|
|
52
55
|
const buffer = globalThis.Buffer.from(encoded, 'base64');
|
|
@@ -25,7 +25,7 @@ declare module '__sveltekit/env' {
|
|
|
25
25
|
// exported environment variables are defined in env.d.ts
|
|
26
26
|
|
|
27
27
|
/** Populate exported environment variables */
|
|
28
|
-
export function set_env(environment: Record<string, string>): void;
|
|
28
|
+
export function set_env(environment: Record<string, string | undefined>): void;
|
|
29
29
|
|
|
30
30
|
/** public env vars */
|
|
31
31
|
export const explicit_public_env: Record<string, any>;
|
|
@@ -51,5 +51,5 @@ declare module '__sveltekit/manifest-data' {
|
|
|
51
51
|
export const immutable: Array<{ path: string }>;
|
|
52
52
|
export const assets: Array<{ path: string }>;
|
|
53
53
|
export const prerendered: Array<{ path: string }>;
|
|
54
|
-
export const routes: Array<{ id: string }>;
|
|
54
|
+
export const routes: Array<{ id: string; page: boolean; endpoint: boolean }>;
|
|
55
55
|
}
|
package/src/types/ambient.d.ts
CHANGED
|
@@ -44,7 +44,7 @@ declare namespace App {
|
|
|
44
44
|
export interface PageData {}
|
|
45
45
|
|
|
46
46
|
/**
|
|
47
|
-
* The shape of the `page.state` object, which can be manipulated using
|
|
47
|
+
* The shape of the `page.state` object, which can be manipulated using [`goto`](https://svelte.dev/docs/kit/$app-navigation#goto).
|
|
48
48
|
*/
|
|
49
49
|
// eslint-disable-next-line @typescript-eslint/no-empty-object-type
|
|
50
50
|
export interface PageState {}
|
|
@@ -78,9 +78,41 @@ declare module '$app/manifest' {
|
|
|
78
78
|
*/
|
|
79
79
|
export const prerendered: Array<{ path: import('$app/types').Path }>;
|
|
80
80
|
/**
|
|
81
|
-
*
|
|
82
|
-
|
|
83
|
-
|
|
81
|
+
* A route in your app, along with its capabilities. `page` indicates the presence of a `+page`,
|
|
82
|
+
* while `endpoint` indicates the presence of a `+server`. Both are `true` when both files exist.
|
|
83
|
+
*/
|
|
84
|
+
export type ManifestRoute =
|
|
85
|
+
| {
|
|
86
|
+
id: Exclude<import('$app/types').PageRouteId, import('$app/types').EndpointRouteId>;
|
|
87
|
+
page: true;
|
|
88
|
+
endpoint: false;
|
|
89
|
+
}
|
|
90
|
+
| {
|
|
91
|
+
id: Exclude<import('$app/types').EndpointRouteId, import('$app/types').PageRouteId>;
|
|
92
|
+
page: false;
|
|
93
|
+
endpoint: true;
|
|
94
|
+
}
|
|
95
|
+
| {
|
|
96
|
+
id: Extract<import('$app/types').PageRouteId, import('$app/types').EndpointRouteId>;
|
|
97
|
+
page: true;
|
|
98
|
+
endpoint: true;
|
|
99
|
+
};
|
|
100
|
+
/**
|
|
101
|
+
* An array of objects representing the routes in your app. Only routes that the router can match
|
|
102
|
+
* are included — directories that merely hold a `+layout` are not routes of their own.
|
|
103
|
+
*
|
|
104
|
+
* Each object has an `id`, plus `page` and `endpoint` booleans describing whether the route has a
|
|
105
|
+
* `+page` and/or a `+server`. Both are `true` for a route that has both, so the capabilities can
|
|
106
|
+
* be filtered independently:
|
|
107
|
+
*
|
|
108
|
+
* ```js
|
|
109
|
+
* import { routes } from '$app/manifest';
|
|
110
|
+
*
|
|
111
|
+
* const pages = routes.filter((route) => route.page);
|
|
112
|
+
* const endpoints = routes.filter((route) => route.endpoint);
|
|
113
|
+
* ```
|
|
114
|
+
*/
|
|
115
|
+
export const routes: ManifestRoute[];
|
|
84
116
|
}
|
|
85
117
|
|
|
86
118
|
/**
|
|
@@ -94,6 +126,8 @@ declare module '$app/types' {
|
|
|
94
126
|
// These are all functions so that we can leverage function overloads to get the correct type.
|
|
95
127
|
// Using the return types directly would error with a "not the same type" error.
|
|
96
128
|
// https://www.typescriptlang.org/docs/handbook/declaration-merging.html#merging-interfaces
|
|
129
|
+
PageRouteId(): string;
|
|
130
|
+
EndpointRouteId(): string;
|
|
97
131
|
RouteId(): string;
|
|
98
132
|
RouteParams(): Record<string, Record<string, string>>;
|
|
99
133
|
LayoutParams(): Record<string, Record<string, string>>;
|
|
@@ -103,7 +137,21 @@ declare module '$app/types' {
|
|
|
103
137
|
}
|
|
104
138
|
|
|
105
139
|
/**
|
|
106
|
-
* A union of
|
|
140
|
+
* A union of the route IDs in your app that have a `+page`.
|
|
141
|
+
*
|
|
142
|
+
* A route ID can be in both `PageRouteId` and `EndpointRouteId`, if its directory contains both a `+page` and a `+server`.
|
|
143
|
+
*/
|
|
144
|
+
export type PageRouteId = ReturnType<AppTypes['PageRouteId']>;
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* A union of the route IDs in your app that have a `+server`.
|
|
148
|
+
*
|
|
149
|
+
* A route ID can be in both `PageRouteId` and `EndpointRouteId`, if its directory contains both a `+page` and a `+server`.
|
|
150
|
+
*/
|
|
151
|
+
export type EndpointRouteId = ReturnType<AppTypes['EndpointRouteId']>;
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* A union of all the route IDs in your app — the union of `PageRouteId` and `EndpointRouteId`. Used for `page.route.id` and `event.route.id`.
|
|
107
155
|
*/
|
|
108
156
|
export type RouteId = ReturnType<AppTypes['RouteId']>;
|
|
109
157
|
|
|
@@ -119,12 +167,15 @@ declare module '$app/types' {
|
|
|
119
167
|
? ReturnType<AppTypes['RouteParams']>[T]
|
|
120
168
|
: Record<string, never>;
|
|
121
169
|
|
|
170
|
+
/**
|
|
171
|
+
* The route IDs accepted by `LayoutParams`. Like `RouteId`, these preserve route groups and `[param]` syntax, but they identify directories containing layouts rather than matchable routes.
|
|
172
|
+
*/
|
|
173
|
+
type LayoutParamsId = keyof ReturnType<AppTypes['LayoutParams']>;
|
|
174
|
+
|
|
122
175
|
/**
|
|
123
176
|
* A utility for getting the parameters associated with a given layout, which is similar to `RouteParams` but also includes optional parameters for any child route.
|
|
124
177
|
*/
|
|
125
|
-
export type LayoutParams<T extends
|
|
126
|
-
? ReturnType<AppTypes['LayoutParams']>[T]
|
|
127
|
-
: Record<string, never>;
|
|
178
|
+
export type LayoutParams<T extends LayoutParamsId> = ReturnType<AppTypes['LayoutParams']>[T];
|
|
128
179
|
|
|
129
180
|
/**
|
|
130
181
|
* A union of all valid paths in your app, relative to the `base` path.
|
|
@@ -53,7 +53,7 @@ declare global {
|
|
|
53
53
|
const __SVELTEKIT_MANIFEST_IMMUTABLE__: string[];
|
|
54
54
|
const __SVELTEKIT_MANIFEST_ASSETS__: string[];
|
|
55
55
|
const __SVELTEKIT_MANIFEST_PRERENDERED__: string[];
|
|
56
|
-
const __SVELTEKIT_MANIFEST_ROUTES__: { id: string }
|
|
56
|
+
const __SVELTEKIT_MANIFEST_ROUTES__: Array<{ id: string }>;
|
|
57
57
|
/**
|
|
58
58
|
* This makes the use of specific features visible at both dev and build time, in such a
|
|
59
59
|
* way that we can error when they are not supported by the target platform.
|
package/src/types/internal.d.ts
CHANGED
|
@@ -239,6 +239,8 @@ export interface PrerenderOptions {
|
|
|
239
239
|
dependencies: Map<string, PrerenderDependency>;
|
|
240
240
|
/** Results of remote `prerender` functions, shared across the whole prerender run so that each only executes once */
|
|
241
241
|
remote_responses: Map<string, Promise<any>>;
|
|
242
|
+
/** Route IDs whose resolution module has been emitted, shared across the whole prerender run so that each only generates once */
|
|
243
|
+
resolved_route_ids: Set<string>;
|
|
242
244
|
/** True for the duration of a call to the `reroute` hook */
|
|
243
245
|
inside_reroute?: boolean;
|
|
244
246
|
}
|
|
@@ -536,7 +538,6 @@ export interface SSRClientRoute {
|
|
|
536
538
|
}
|
|
537
539
|
|
|
538
540
|
export interface SSRState {
|
|
539
|
-
fallback?: string;
|
|
540
541
|
getClientAddress(): string;
|
|
541
542
|
/**
|
|
542
543
|
* True if we're currently attempting to render an error page.
|
|
@@ -659,15 +660,10 @@ export interface RemotePrerenderInternals extends BaseRemoteInternals {
|
|
|
659
660
|
}
|
|
660
661
|
|
|
661
662
|
export type RemoteAnyQueryInternals =
|
|
662
|
-
|
|
|
663
|
-
| RemoteQueryBatchInternals
|
|
664
|
-
| RemoteQueryLiveInternals;
|
|
663
|
+
RemoteQueryInternals | RemoteQueryBatchInternals | RemoteQueryLiveInternals;
|
|
665
664
|
|
|
666
665
|
export type RemoteInternals =
|
|
667
|
-
|
|
|
668
|
-
| RemoteCommandInternals
|
|
669
|
-
| RemoteFormInternals
|
|
670
|
-
| RemotePrerenderInternals;
|
|
666
|
+
RemoteAnyQueryInternals | RemoteCommandInternals | RemoteFormInternals | RemotePrerenderInternals;
|
|
671
667
|
|
|
672
668
|
export interface InternalRemoteFormIssue extends RemoteFormIssue {
|
|
673
669
|
name: string;
|
package/src/types/private.d.ts
CHANGED
|
@@ -239,20 +239,11 @@ export interface PrerenderInvalidUrlHandler {
|
|
|
239
239
|
export type PrerenderHttpErrorHandlerValue = 'fail' | 'warn' | 'ignore' | PrerenderHttpErrorHandler;
|
|
240
240
|
export type PrerenderMissingIdHandlerValue = 'fail' | 'warn' | 'ignore' | PrerenderMissingIdHandler;
|
|
241
241
|
export type PrerenderUnseenRoutesHandlerValue =
|
|
242
|
-
| '
|
|
243
|
-
| 'warn'
|
|
244
|
-
| 'ignore'
|
|
245
|
-
| PrerenderUnseenRoutesHandler;
|
|
242
|
+
'fail' | 'warn' | 'ignore' | PrerenderUnseenRoutesHandler;
|
|
246
243
|
export type PrerenderEntryGeneratorMismatchHandlerValue =
|
|
247
|
-
| '
|
|
248
|
-
| 'warn'
|
|
249
|
-
| 'ignore'
|
|
250
|
-
| PrerenderEntryGeneratorMismatchHandler;
|
|
244
|
+
'fail' | 'warn' | 'ignore' | PrerenderEntryGeneratorMismatchHandler;
|
|
251
245
|
export type PrerenderInvalidUrlHandlerValue =
|
|
252
|
-
| '
|
|
253
|
-
| 'warn'
|
|
254
|
-
| 'ignore'
|
|
255
|
-
| PrerenderInvalidUrlHandler;
|
|
246
|
+
'fail' | 'warn' | 'ignore' | PrerenderInvalidUrlHandler;
|
|
256
247
|
|
|
257
248
|
export type PrerenderOption = boolean | 'auto';
|
|
258
249
|
|