@sveltejs/kit 3.0.0-next.7 → 3.0.0-next.9
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 +6 -3
- package/src/core/config/index.js +1 -2
- package/src/core/config/options.js +5 -2
- package/src/core/env.js +1 -0
- package/src/core/sync/create_manifest_data/index.js +1 -1
- package/src/core/sync/sync.js +0 -2
- package/src/core/sync/write_client_manifest.js +0 -7
- package/src/core/sync/write_non_ambient.js +2 -2
- package/src/core/sync/write_server.js +0 -3
- package/src/core/sync/write_tsconfig.js +14 -4
- package/src/core/sync/write_tsconfig_test/package.json +7 -0
- package/src/core/sync/write_types/index.js +17 -14
- package/src/core/utils.js +2 -2
- package/src/exports/hooks/sequence.js +3 -2
- package/src/exports/index.js +1 -1
- package/src/exports/node/index.js +4 -8
- package/src/exports/public.d.ts +22 -23
- package/src/exports/vite/dev/index.js +4 -7
- package/src/exports/vite/index.js +110 -59
- package/src/exports/vite/preview/index.js +13 -14
- package/src/exports/vite/utils.js +14 -14
- package/src/runtime/app/env/internal.js +4 -4
- package/src/runtime/app/environment/index.js +3 -3
- package/src/runtime/app/forms.js +2 -2
- package/src/runtime/app/paths/internal/client.js +4 -2
- package/src/runtime/app/paths/internal/server.js +2 -23
- package/src/runtime/app/paths/server.js +2 -2
- package/src/runtime/app/server/remote/prerender.js +1 -2
- package/src/runtime/client/bundle.js +1 -1
- package/src/runtime/client/client-entry.js +3 -0
- package/src/runtime/client/client.js +217 -172
- package/src/runtime/client/entry.js +24 -3
- package/src/runtime/client/payload.js +17 -0
- package/src/runtime/client/remote-functions/form.svelte.js +6 -6
- package/src/runtime/client/state.svelte.js +0 -1
- package/src/runtime/client/types.d.ts +2 -6
- package/src/runtime/components/root.svelte +66 -0
- package/src/runtime/env/dynamic/private.js +7 -0
- package/src/runtime/env/dynamic/public.js +7 -0
- package/src/runtime/env/static/private.js +6 -0
- package/src/runtime/env/static/public.js +6 -0
- package/src/runtime/form-utils.js +1 -4
- package/src/runtime/server/cookie.js +51 -23
- package/src/runtime/server/csrf.js +1 -1
- package/src/runtime/server/data/index.js +8 -12
- package/src/runtime/server/page/index.js +7 -14
- package/src/runtime/server/page/render.js +71 -78
- package/src/runtime/server/remote.js +2 -1
- package/src/runtime/server/respond.js +1 -1
- package/src/runtime/server/utils.js +28 -5
- package/src/runtime/types.d.ts +8 -0
- package/src/types/global-private.d.ts +10 -17
- package/src/types/internal.d.ts +25 -26
- package/src/utils/import.js +6 -1
- package/src/utils/imports.js +83 -0
- package/src/utils/routing.js +6 -6
- package/src/version.js +1 -1
- package/types/index.d.ts +34 -285
- package/types/index.d.ts.map +3 -26
- package/src/core/sync/write_root.js +0 -127
- package/src/types/synthetic/$lib.md +0 -5
|
@@ -1,5 +1,5 @@
|
|
|
1
|
+
/** @import { RenderNode } from '../../types.js' */
|
|
1
2
|
import * as devalue from 'devalue';
|
|
2
|
-
import { readable, writable } from 'svelte/store';
|
|
3
3
|
import { DEV } from 'esm-env';
|
|
4
4
|
import { isRedirect, text } from '@sveltejs/kit';
|
|
5
5
|
import * as paths from '$app/paths/internal/server';
|
|
@@ -22,14 +22,11 @@ import {
|
|
|
22
22
|
} from '../utils.js';
|
|
23
23
|
import * as env from '__sveltekit/env';
|
|
24
24
|
import { collect_remote_data } from '../remote.js';
|
|
25
|
+
import Root from '../../components/root.svelte';
|
|
26
|
+
import { render } from 'svelte/server';
|
|
25
27
|
|
|
26
28
|
// TODO rename this function/module
|
|
27
29
|
|
|
28
|
-
const updated = {
|
|
29
|
-
...readable(false),
|
|
30
|
-
check: () => false
|
|
31
|
-
};
|
|
32
|
-
|
|
33
30
|
/**
|
|
34
31
|
* Creates the HTML response.
|
|
35
32
|
* @param {{
|
|
@@ -46,7 +43,7 @@ const updated = {
|
|
|
46
43
|
* resolve_opts: import('types').RequiredResolveOptions;
|
|
47
44
|
* action_result?: import('@sveltejs/kit').ActionResult;
|
|
48
45
|
* data_serializer: import('./types.js').ServerDataSerializer;
|
|
49
|
-
* error_components?: Array<import('
|
|
46
|
+
* error_components?: Array<import('svelte').Component | undefined>
|
|
50
47
|
* }} opts
|
|
51
48
|
*/
|
|
52
49
|
export async function render_response({
|
|
@@ -91,7 +88,8 @@ export async function render_response({
|
|
|
91
88
|
// TODO if we add a client entry point one day, we will need to include inline_styles with the entry, otherwise stylesheets will be linked even if they are below inlineStyleThreshold
|
|
92
89
|
const inline_styles = new Map();
|
|
93
90
|
|
|
94
|
-
|
|
91
|
+
// TODO `svelte/server` should expose `RenderOutput`
|
|
92
|
+
/** @type {{ head: string, body: string, hashes: { script: string[] } }} */
|
|
95
93
|
let rendered;
|
|
96
94
|
|
|
97
95
|
const form_value =
|
|
@@ -142,49 +140,47 @@ export async function render_response({
|
|
|
142
140
|
if (page_config.ssr) {
|
|
143
141
|
/** @type {Record<string, any>} */
|
|
144
142
|
const props = {
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
form: form_value
|
|
160
|
-
};
|
|
161
|
-
|
|
162
|
-
if (error_components) {
|
|
163
|
-
if (error) {
|
|
164
|
-
props.error = error;
|
|
143
|
+
components: [],
|
|
144
|
+
resetters: [],
|
|
145
|
+
form: form_value,
|
|
146
|
+
tree: /** @type {RenderNode} */ ({}),
|
|
147
|
+
error,
|
|
148
|
+
page: {
|
|
149
|
+
error,
|
|
150
|
+
params: /** @type {Record<string, any>} */ (event.params),
|
|
151
|
+
route: event.route,
|
|
152
|
+
status,
|
|
153
|
+
url: event.url,
|
|
154
|
+
data: {},
|
|
155
|
+
form: form_value,
|
|
156
|
+
state: {}
|
|
165
157
|
}
|
|
166
|
-
|
|
167
|
-
}
|
|
158
|
+
};
|
|
168
159
|
|
|
169
|
-
let
|
|
160
|
+
let current_node = props.tree;
|
|
161
|
+
let data = props.page.data;
|
|
170
162
|
|
|
171
|
-
// props_n (instead of props[n]) makes it easy to avoid
|
|
172
|
-
// unnecessary updates for layout components
|
|
173
163
|
for (let i = 0; i < branch.length; i += 1) {
|
|
174
|
-
|
|
175
|
-
|
|
164
|
+
const node = branch[i];
|
|
165
|
+
|
|
166
|
+
data = { ...data, ...node.data };
|
|
167
|
+
|
|
168
|
+
// TODO this is undefined sometimes... where does the default error component come from?
|
|
169
|
+
const error = error_components?.slice(0, i + 1).findLast((x) => x);
|
|
170
|
+
|
|
171
|
+
current_node.error = error;
|
|
172
|
+
current_node.component = await node.node.component?.();
|
|
173
|
+
current_node.data = data;
|
|
174
|
+
|
|
175
|
+
if (i < branch.length - 1) {
|
|
176
|
+
current_node.child = /** @type {import('../../types.js').RenderNode} */ ({});
|
|
177
|
+
current_node = current_node.child;
|
|
178
|
+
}
|
|
176
179
|
}
|
|
177
180
|
|
|
178
|
-
props.page =
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
route: event.route,
|
|
182
|
-
status,
|
|
183
|
-
url: event.url,
|
|
184
|
-
data,
|
|
185
|
-
form: form_value,
|
|
186
|
-
state: {}
|
|
187
|
-
};
|
|
181
|
+
props.page.data = data;
|
|
182
|
+
|
|
183
|
+
const render_state = { ...event_state, is_in_render: true };
|
|
188
184
|
|
|
189
185
|
const render_opts = {
|
|
190
186
|
context: new Map([
|
|
@@ -197,15 +193,28 @@ export async function render_response({
|
|
|
197
193
|
]),
|
|
198
194
|
csp: csp.script_needs_nonce ? { nonce: csp.nonce } : { hash: csp.script_needs_hash },
|
|
199
195
|
transformError: error_components
|
|
200
|
-
? /** @param {unknown} e */
|
|
196
|
+
? /** @param {unknown} e */ (e) => {
|
|
201
197
|
if (isRedirect(e)) {
|
|
202
198
|
throw e;
|
|
203
199
|
}
|
|
204
200
|
|
|
205
|
-
const
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
201
|
+
const handled = handle_error_and_jsonify(event, render_state, options, e);
|
|
202
|
+
|
|
203
|
+
// TODO 4.0 make this an async function and await `handled`
|
|
204
|
+
if (handled instanceof Promise) {
|
|
205
|
+
return handled.then((e) => {
|
|
206
|
+
error = e;
|
|
207
|
+
props.page.error = error;
|
|
208
|
+
props.page.status = status = error.status;
|
|
209
|
+
return error;
|
|
210
|
+
});
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
error = handled;
|
|
214
|
+
props.page.error = error;
|
|
215
|
+
props.page.status = status = error.status;
|
|
216
|
+
|
|
217
|
+
return error;
|
|
209
218
|
}
|
|
210
219
|
: undefined
|
|
211
220
|
};
|
|
@@ -231,44 +240,27 @@ export async function render_response({
|
|
|
231
240
|
};
|
|
232
241
|
}
|
|
233
242
|
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
rendered = await with_request_store({ event, state }, async () => {
|
|
237
|
-
// use relative paths during rendering, so that the resulting HTML is as
|
|
238
|
-
// portable as possible, but reset afterwards
|
|
239
|
-
if (paths.relative) paths.override({ base, assets });
|
|
240
|
-
|
|
243
|
+
rendered = await with_request_store({ event, state: render_state }, async () => {
|
|
241
244
|
// We have to invoke .then eagerly here in order to kick off rendering: it's only starting on access,
|
|
242
245
|
// and `await maybe_promise` would eagerly access the .then property but call its function only after a tick, which is too late
|
|
243
246
|
// for the paths.reset() below and for any eager getRequestEvent() calls during rendering without AsyncLocalStorage available.
|
|
244
|
-
|
|
245
|
-
const rendered = options.root.render(props, render_opts).then((r) => r);
|
|
246
|
-
|
|
247
|
-
// we reset this synchronously, rather than after async rendering is complete,
|
|
248
|
-
// to avoid cross-talk between requests. This is a breaking change for
|
|
249
|
-
// anyone who opts into async SSR, since `base` and `assets` will no
|
|
250
|
-
// longer be relative to the current pathname.
|
|
251
|
-
// TODO 3.0 remove `base` and `assets` in favour of `resolve(...)` and `asset(...)`
|
|
252
|
-
paths.reset();
|
|
247
|
+
const rendered = render(Root, { ...render_opts, props });
|
|
253
248
|
|
|
254
|
-
|
|
255
|
-
const { head, html: body, css, hashes } = await rendered;
|
|
249
|
+
const { head, body, hashes } = await rendered;
|
|
256
250
|
|
|
257
251
|
if (hashes) {
|
|
258
252
|
csp.add_script_hashes(hashes.script);
|
|
259
253
|
}
|
|
260
254
|
|
|
261
|
-
return { head, body,
|
|
255
|
+
return { head, body, hashes };
|
|
262
256
|
});
|
|
263
257
|
} finally {
|
|
264
258
|
if (DEV) {
|
|
265
259
|
globalThis.fetch = fetch;
|
|
266
260
|
}
|
|
267
|
-
|
|
268
|
-
paths.reset(); // just in case `options.root.render(...)` failed
|
|
269
261
|
}
|
|
270
262
|
} else {
|
|
271
|
-
rendered = { head: '', body: '',
|
|
263
|
+
rendered = { head: '', body: '', hashes: { script: [] } };
|
|
272
264
|
}
|
|
273
265
|
|
|
274
266
|
for (const { node } of branch) {
|
|
@@ -412,7 +404,7 @@ export async function render_response({
|
|
|
412
404
|
|
|
413
405
|
const blocks = [];
|
|
414
406
|
|
|
415
|
-
const properties = [`base: ${base_expression}`];
|
|
407
|
+
const properties = [`base: ${base_expression}`, `version: ${s(__SVELTEKIT_APP_VERSION__)}`];
|
|
416
408
|
|
|
417
409
|
if (paths.assets) {
|
|
418
410
|
properties.push(`assets: ${s(paths.assets)}`);
|
|
@@ -435,7 +427,9 @@ export async function render_response({
|
|
|
435
427
|
if (client.inline) {
|
|
436
428
|
app_declaration = `const app = ${global}.app.app;`;
|
|
437
429
|
} else if (client.app) {
|
|
438
|
-
app_declaration = `const
|
|
430
|
+
app_declaration = `const kit = await import(${s(prefixed(client.start))});
|
|
431
|
+
kit.init(${global});
|
|
432
|
+
const app = await import(${s(prefixed(client.app))});`;
|
|
439
433
|
} else {
|
|
440
434
|
app_declaration = `const { app } = await import(${s(prefixed(client.start))});`;
|
|
441
435
|
}
|
|
@@ -529,10 +523,9 @@ export async function render_response({
|
|
|
529
523
|
|
|
530
524
|
${serialized_data}${global}.app.start(${args.join(', ')});`
|
|
531
525
|
: client.app
|
|
532
|
-
? `
|
|
533
|
-
|
|
534
|
-
import(${s(prefixed(client.app))})
|
|
535
|
-
]).then(([kit, app]) => {
|
|
526
|
+
? `import(${s(prefixed(client.start))}).then(async (kit) => {
|
|
527
|
+
kit.init(${global});
|
|
528
|
+
const app = await import(${s(prefixed(client.app))});
|
|
536
529
|
${serialized_data}kit.start(app, ${args.join(', ')});
|
|
537
530
|
});`
|
|
538
531
|
: `import(${s(prefixed(client.start))}).then((app) => {
|
|
@@ -361,7 +361,8 @@ export async function collect_remote_data(data, event, state, options) {
|
|
|
361
361
|
* @returns {Promise<App.Error>}
|
|
362
362
|
*/
|
|
363
363
|
function convert_error(error) {
|
|
364
|
-
|
|
364
|
+
// TODO 4.0 remove the `Promise.resolve(...)`
|
|
365
|
+
return Promise.resolve(handle_error_and_jsonify(event, state, options, error));
|
|
365
366
|
}
|
|
366
367
|
|
|
367
368
|
/** @type {Promise<any>[]} */
|
|
@@ -70,7 +70,7 @@ export async function internal_respond(request, options, manifest, state) {
|
|
|
70
70
|
const is_data_request = has_data_suffix(url.pathname);
|
|
71
71
|
const remote_id = get_remote_id(url);
|
|
72
72
|
|
|
73
|
-
if (!
|
|
73
|
+
if (!__SVELTEKIT_DEV__) {
|
|
74
74
|
const request_origin = request.headers.get('origin');
|
|
75
75
|
const self_origin = get_self_origin(options.paths_origin, url.origin);
|
|
76
76
|
|
|
@@ -98,9 +98,9 @@ export async function handle_fatal_error(event, state, options, error) {
|
|
|
98
98
|
* @param {import('types').RequestState} state
|
|
99
99
|
* @param {import('types').SSROptions} options
|
|
100
100
|
* @param {any} error
|
|
101
|
-
* @returns {Promise<App.Error>}
|
|
101
|
+
* @returns {App.Error | Promise<App.Error>}
|
|
102
102
|
*/
|
|
103
|
-
export
|
|
103
|
+
export function handle_error_and_jsonify(event, state, options, error) {
|
|
104
104
|
if (error instanceof HttpError) {
|
|
105
105
|
// @ts-expect-error custom user errors may not have a message field if App.Error is overwritten
|
|
106
106
|
return { message: 'Unknown Error', ...error.body };
|
|
@@ -113,11 +113,34 @@ export async function handle_error_and_jsonify(event, state, options, error) {
|
|
|
113
113
|
const status = get_status(error);
|
|
114
114
|
const message = get_message(error);
|
|
115
115
|
|
|
116
|
-
|
|
116
|
+
// TODO 4.0 await this, rather than handling the non-Promise case
|
|
117
|
+
const result = with_request_store({ event, state }, () =>
|
|
117
118
|
options.hooks.handleError({ error, event, status, message })
|
|
118
|
-
)
|
|
119
|
+
) ?? { status, message };
|
|
120
|
+
|
|
121
|
+
if (result instanceof Promise) {
|
|
122
|
+
if (!__SVELTEKIT_SUPPORTS_ASYNC__ && state.is_in_render) {
|
|
123
|
+
console.warn(
|
|
124
|
+
`To use an async \`handleError\` hook to handle errors that occur during rendering, you must enable \`compilerOptions.experimental.async\` in the SvelteKit plugin of your Vite config. The returned error has been replaced with a generic object`
|
|
125
|
+
);
|
|
126
|
+
|
|
127
|
+
// we're discarding the result, but we still need to prevent an unhandled
|
|
128
|
+
// rejection if the user's async `handleError` hook rejects
|
|
129
|
+
result.catch(() => {});
|
|
130
|
+
|
|
131
|
+
return {
|
|
132
|
+
status,
|
|
133
|
+
message: 'Internal Error'
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
return result.then((body) => {
|
|
138
|
+
body ??= { status, message };
|
|
139
|
+
return { ...body, status: get_status(body, error) };
|
|
140
|
+
});
|
|
141
|
+
}
|
|
119
142
|
|
|
120
|
-
return { ...
|
|
143
|
+
return { ...result, status: get_status(result, error) };
|
|
121
144
|
}
|
|
122
145
|
|
|
123
146
|
/**
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { SvelteKitPayload } from 'types';
|
|
2
2
|
|
|
3
3
|
declare global {
|
|
4
4
|
const __SVELTEKIT_ADAPTER_NAME__: string;
|
|
@@ -33,26 +33,20 @@ declare global {
|
|
|
33
33
|
* Used for treeshaking universal load code from client bundles when no universal loads exist.
|
|
34
34
|
*/
|
|
35
35
|
const __SVELTEKIT_HAS_UNIVERSAL_LOAD__: boolean;
|
|
36
|
-
/**
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
assets?: string;
|
|
42
|
-
/** Public environment variables */
|
|
43
|
-
env?: Record<string, string>;
|
|
44
|
-
/** Serialized data from query/form/command functions */
|
|
45
|
-
data?: RemoteFunctionData;
|
|
46
|
-
/** Create a placeholder promise */
|
|
47
|
-
defer?: (id: number) => Promise<any>;
|
|
48
|
-
/** Resolve a placeholder promise */
|
|
49
|
-
resolve?: (data: { id: number; data: any; error: any }) => void;
|
|
50
|
-
};
|
|
36
|
+
/**
|
|
37
|
+
* The `__sveltekit_abc123` object in the init `<script>`.
|
|
38
|
+
* Should only be used when bundleStrategy !== 'inline' to avoid SvelteKit runtime changing on every build, preventing cacheability.
|
|
39
|
+
*/
|
|
40
|
+
const __SVELTEKIT_PAYLOAD__: SvelteKitPayload;
|
|
51
41
|
/**
|
|
52
42
|
* The Vite `root` setting used to construct paths to nodes and components
|
|
53
43
|
* for the SSR manifest during development
|
|
54
44
|
*/
|
|
55
45
|
const __SVELTEKIT_ROOT__: string;
|
|
46
|
+
/**
|
|
47
|
+
* Whether the `experimental.async` flag is applied
|
|
48
|
+
*/
|
|
49
|
+
const __SVELTEKIT_SUPPORTS_ASYNC__: boolean;
|
|
56
50
|
/**
|
|
57
51
|
* This makes the use of specific features visible at both dev and build time, in such a
|
|
58
52
|
* way that we can error when they are not supported by the target platform.
|
|
@@ -68,7 +62,6 @@ declare global {
|
|
|
68
62
|
* to throw an error if the feature would fail in production.
|
|
69
63
|
*/
|
|
70
64
|
var __SVELTEKIT_TRACK__: (label: string) => void;
|
|
71
|
-
var __SVELTEKIT_EXPERIMENTAL_USE_TRANSFORM_ERROR__: boolean;
|
|
72
65
|
var Bun: object;
|
|
73
66
|
var Deno: object;
|
|
74
67
|
}
|
package/src/types/internal.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Component } from 'svelte';
|
|
2
2
|
import {
|
|
3
3
|
Config,
|
|
4
4
|
ServerLoad,
|
|
@@ -113,7 +113,7 @@ export interface BuildData {
|
|
|
113
113
|
}
|
|
114
114
|
|
|
115
115
|
export interface CSRPageNode {
|
|
116
|
-
component:
|
|
116
|
+
component: Component;
|
|
117
117
|
universal: {
|
|
118
118
|
load?: Load;
|
|
119
119
|
trailingSlash?: TrailingSlash;
|
|
@@ -417,27 +417,7 @@ export interface ServerMetadata {
|
|
|
417
417
|
remotes: Map<string, Map<string, { type: RemoteInternals['type']; dynamic: boolean }>>;
|
|
418
418
|
}
|
|
419
419
|
|
|
420
|
-
|
|
421
|
-
export interface SSRComponent {
|
|
422
|
-
default: {
|
|
423
|
-
render(
|
|
424
|
-
props: Record<string, any>,
|
|
425
|
-
opts: { context: Map<any, any>; csp?: { nonce?: string; hash?: boolean } }
|
|
426
|
-
): Promise<{
|
|
427
|
-
body: string;
|
|
428
|
-
head: string;
|
|
429
|
-
css: {
|
|
430
|
-
code: string;
|
|
431
|
-
map: any; // TODO
|
|
432
|
-
};
|
|
433
|
-
hashes: {
|
|
434
|
-
script: Array<`sha256-${string}`>;
|
|
435
|
-
};
|
|
436
|
-
}>;
|
|
437
|
-
};
|
|
438
|
-
}
|
|
439
|
-
|
|
440
|
-
export type SSRComponentLoader = () => Promise<SSRComponent>;
|
|
420
|
+
export type SSRComponentLoader = () => Promise<Component>;
|
|
441
421
|
|
|
442
422
|
export interface UniversalNode {
|
|
443
423
|
/** Is `null` in case static analysis succeeds but the node is ssr=false */
|
|
@@ -476,7 +456,10 @@ export interface SSRNode {
|
|
|
476
456
|
|
|
477
457
|
/**
|
|
478
458
|
* During development, all styles are inlined for the page to avoid FOUC.
|
|
479
|
-
* But in production, this stores styles that are below the inline threshold
|
|
459
|
+
* But in production, this stores styles that are below the inline threshold.
|
|
460
|
+
* It returns a Promise during development because Vite needs to load the
|
|
461
|
+
* modules on demand. But in production, the contents have been precomputed
|
|
462
|
+
* during the build, so it can return synchronously.
|
|
480
463
|
*/
|
|
481
464
|
inline_styles?(): MaybePromise<
|
|
482
465
|
Record<string, string | ((assets: string, base: string) => string)>
|
|
@@ -501,10 +484,8 @@ export interface SSROptions {
|
|
|
501
484
|
hooks: ServerHooks;
|
|
502
485
|
link_header_preload: ValidatedConfig['kit']['output']['linkHeaderPreload'];
|
|
503
486
|
paths_origin: string | undefined;
|
|
504
|
-
root: SSRComponent['default'];
|
|
505
487
|
service_worker: boolean;
|
|
506
488
|
service_worker_options: RegistrationOptions;
|
|
507
|
-
server_error_boundaries: boolean;
|
|
508
489
|
templates: {
|
|
509
490
|
app(values: {
|
|
510
491
|
head: string;
|
|
@@ -764,5 +745,23 @@ export interface RequestStore {
|
|
|
764
745
|
state: RequestState;
|
|
765
746
|
}
|
|
766
747
|
|
|
748
|
+
/** Type of the `__sveltekit_abc123` object in the init `<script>` */
|
|
749
|
+
export interface SvelteKitPayload {
|
|
750
|
+
/** The application version */
|
|
751
|
+
version: string;
|
|
752
|
+
/** The basepath, usually relative to the current page */
|
|
753
|
+
base: string;
|
|
754
|
+
/** Path to externally-hosted assets */
|
|
755
|
+
assets?: string;
|
|
756
|
+
/** Public environment variables */
|
|
757
|
+
env?: Record<string, string>;
|
|
758
|
+
/** Serialized data from query/form/command functions */
|
|
759
|
+
data?: RemoteFunctionData;
|
|
760
|
+
/** Create a placeholder promise */
|
|
761
|
+
defer?: (id: number) => Promise<any>;
|
|
762
|
+
/** Resolve a placeholder promise */
|
|
763
|
+
resolve?: (data: { id: number; data: any; error: any }) => void;
|
|
764
|
+
}
|
|
765
|
+
|
|
767
766
|
export * from '../exports/index.js';
|
|
768
767
|
export * from './private.js';
|
package/src/utils/import.js
CHANGED
|
@@ -2,7 +2,12 @@ import fs from 'node:fs';
|
|
|
2
2
|
import path from 'node:path';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
|
-
* Resolves a peer dependency relative to the current working directory.
|
|
5
|
+
* Resolves a peer dependency relative to the current working directory.
|
|
6
|
+
*
|
|
7
|
+
* Mainly used to resolve the correct Vite package when an app's SvelteKit is a
|
|
8
|
+
* linked local repository.
|
|
9
|
+
*
|
|
10
|
+
* Duplicated with `packages/adapter-auto`
|
|
6
11
|
* @param {string} dependency
|
|
7
12
|
* @param {string} root
|
|
8
13
|
*/
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Reads the `imports` field from the package.json at the given directory.
|
|
6
|
+
* @param {string} cwd
|
|
7
|
+
* @returns {Record<string, string | Record<string, string>> | undefined}
|
|
8
|
+
*/
|
|
9
|
+
export function read_package_imports(cwd) {
|
|
10
|
+
const pkg_path = path.resolve(cwd, 'package.json');
|
|
11
|
+
if (fs.existsSync(pkg_path)) {
|
|
12
|
+
try {
|
|
13
|
+
return JSON.parse(fs.readFileSync(pkg_path, 'utf-8')).imports;
|
|
14
|
+
} catch {
|
|
15
|
+
// malformed package.json — ignore, the user will see other errors
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Normalizes an import value to a string path, handling both string values
|
|
22
|
+
* and conditional export objects (using the `default` key).
|
|
23
|
+
* @param {string | Record<string, string>} value
|
|
24
|
+
* @returns {string | null}
|
|
25
|
+
*/
|
|
26
|
+
export function normalize_import_value(value) {
|
|
27
|
+
if (typeof value === 'string') {
|
|
28
|
+
return value.replace(/^\.\//, '');
|
|
29
|
+
}
|
|
30
|
+
if (value && typeof value === 'object' && typeof value.default === 'string') {
|
|
31
|
+
return value.default.replace(/^\.\//, '');
|
|
32
|
+
}
|
|
33
|
+
return null;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Returns the `#`-prefixed import keys from the package.json `imports` field.
|
|
38
|
+
* @param {string} cwd
|
|
39
|
+
* @returns {string[]}
|
|
40
|
+
*/
|
|
41
|
+
export function get_hash_import_keys(cwd) {
|
|
42
|
+
const imports = read_package_imports(cwd);
|
|
43
|
+
if (!imports) return [];
|
|
44
|
+
return Object.keys(imports).filter((key) => key.startsWith('#'));
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Computes alias entries for `normalize_id` from the package.json `imports` field.
|
|
49
|
+
* Each entry maps a `#xx` alias to its absolute target path. Entries are sorted
|
|
50
|
+
* by path length descending so that longer/more-specific paths are matched first.
|
|
51
|
+
*
|
|
52
|
+
* @param {string} root
|
|
53
|
+
* @param {(p: string) => string} [normalize] - optional path normalizer (e.g. `vite.normalizePath`)
|
|
54
|
+
* @returns {Array<{ alias: string, path: string }>}
|
|
55
|
+
*/
|
|
56
|
+
export function get_import_aliases(root, normalize) {
|
|
57
|
+
const imports = read_package_imports(root);
|
|
58
|
+
if (!imports) return [];
|
|
59
|
+
|
|
60
|
+
/** @type {Array<{ alias: string, path: string }>} */
|
|
61
|
+
const aliases = [];
|
|
62
|
+
|
|
63
|
+
for (const [key, raw_value] of Object.entries(imports)) {
|
|
64
|
+
if (!key.startsWith('#')) continue;
|
|
65
|
+
|
|
66
|
+
const value = normalize_import_value(raw_value);
|
|
67
|
+
if (!value) continue;
|
|
68
|
+
|
|
69
|
+
// For `#xx/*` imports, the target directory is the value without `/*`
|
|
70
|
+
// For `#xx` imports, the target is the file itself
|
|
71
|
+
const target = value.endsWith('/*') ? value.slice(0, -2) : value;
|
|
72
|
+
if (target.includes('*')) continue; // not sure if this is even allowed in Node, anyway it's too niche/complex to support here
|
|
73
|
+
const abs = path.resolve(root, target);
|
|
74
|
+
const alias = key.endsWith('/*') ? key.slice(0, -2) : key;
|
|
75
|
+
|
|
76
|
+
aliases.push({ alias, path: normalize ? normalize(abs) : abs });
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// Sort by path length descending so longer/more-specific paths match first
|
|
80
|
+
aliases.sort((a, b) => b.path.length - a.path.length);
|
|
81
|
+
|
|
82
|
+
return aliases;
|
|
83
|
+
}
|
package/src/utils/routing.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { BROWSER } from 'esm-env';
|
|
2
2
|
|
|
3
|
-
const param_pattern = /^(\[)?(\.\.\.)?(\w+)(?:=(\w+))?(\])?$/;
|
|
3
|
+
const param_pattern = /^(\[)?(\.\.\.)?([\w-]+)(?:=([\w-]+))?(\])?$/;
|
|
4
4
|
|
|
5
5
|
const root_group_pattern = /^\/\((?:[^)]+)\)$/;
|
|
6
6
|
|
|
@@ -19,7 +19,7 @@ export function parse_route_id(id) {
|
|
|
19
19
|
`^${get_route_segments(id)
|
|
20
20
|
.map((segment) => {
|
|
21
21
|
// special case — /[...rest]/ could contain zero segments
|
|
22
|
-
const rest_match = /^\[\.\.\.(\w+)(?:=(\w+))?\]$/.exec(segment);
|
|
22
|
+
const rest_match = /^\[\.\.\.([\w-]+)(?:=([\w-]+))?\]$/.exec(segment);
|
|
23
23
|
if (rest_match) {
|
|
24
24
|
params.push({
|
|
25
25
|
name: rest_match[1],
|
|
@@ -31,7 +31,7 @@ export function parse_route_id(id) {
|
|
|
31
31
|
return '(?:/([^]*))?';
|
|
32
32
|
}
|
|
33
33
|
// special case — /[[optional]]/ could contain zero segments
|
|
34
|
-
const optional_match = /^\[\[(\w+)(?:=(\w+))?\]\]$/.exec(segment);
|
|
34
|
+
const optional_match = /^\[\[([\w-]+)(?:=([\w-]+))?\]\]$/.exec(segment);
|
|
35
35
|
if (optional_match) {
|
|
36
36
|
params.push({
|
|
37
37
|
name: optional_match[1],
|
|
@@ -72,7 +72,7 @@ export function parse_route_id(id) {
|
|
|
72
72
|
const match = /** @type {RegExpExecArray} */ (param_pattern.exec(content));
|
|
73
73
|
if (!BROWSER && !match) {
|
|
74
74
|
throw new Error(
|
|
75
|
-
`Invalid param: ${content}. Params and matcher names can only have underscores and alphanumeric characters.`
|
|
75
|
+
`Invalid param: ${content}. Params and matcher names can only have underscores, hyphens, and alphanumeric characters.`
|
|
76
76
|
);
|
|
77
77
|
}
|
|
78
78
|
|
|
@@ -103,7 +103,7 @@ export function parse_route_id(id) {
|
|
|
103
103
|
return { pattern, params };
|
|
104
104
|
}
|
|
105
105
|
|
|
106
|
-
const optional_param_regex = /\/\[\[\w+?(
|
|
106
|
+
const optional_param_regex = /\/\[\[[\w-]+?(?:=[\w-]+)?\]\]/;
|
|
107
107
|
|
|
108
108
|
/**
|
|
109
109
|
* Removes optional params from a route ID.
|
|
@@ -260,7 +260,7 @@ function escape(str) {
|
|
|
260
260
|
);
|
|
261
261
|
}
|
|
262
262
|
|
|
263
|
-
const basic_param_pattern = /\[(\[)?(\.\.\.)?(\w+?)(?:=(\w+))?\]\]?/g;
|
|
263
|
+
const basic_param_pattern = /\[(\[)?(\.\.\.)?([\w-]+?)(?:=([\w-]+))?\]\]?/g;
|
|
264
264
|
|
|
265
265
|
/**
|
|
266
266
|
* Populate a route ID with params to resolve a pathname.
|
package/src/version.js
CHANGED