@sveltejs/kit 3.0.0-next.6 → 3.0.0-next.8
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 +8 -3
- package/src/core/adapt/builder.js +11 -39
- package/src/core/config/index.js +76 -71
- package/src/core/config/options.js +280 -285
- package/src/core/config/types.d.ts +1 -1
- package/src/core/env.js +86 -1
- package/src/core/generate_manifest/index.js +12 -15
- package/src/core/sync/create_manifest_data/index.js +7 -45
- package/src/core/sync/sync.js +0 -2
- package/src/core/sync/write_client_manifest.js +7 -21
- package/src/core/sync/write_non_ambient.js +12 -9
- package/src/core/sync/write_server.js +0 -4
- package/src/core/sync/write_types/index.js +28 -24
- package/src/core/utils.js +2 -2
- package/src/exports/index.js +3 -3
- package/src/exports/internal/client.js +5 -0
- package/src/exports/internal/index.js +1 -91
- package/src/exports/internal/{event.js → server/event.js} +1 -2
- package/src/exports/internal/server/index.js +33 -0
- package/src/exports/internal/shared.js +89 -0
- package/src/exports/node/index.js +5 -9
- package/src/exports/params.js +63 -0
- package/src/exports/public.d.ts +103 -46
- package/src/exports/url.js +84 -0
- package/src/exports/vite/dev/index.js +31 -20
- package/src/exports/vite/index.js +280 -199
- package/src/exports/vite/preview/index.js +14 -15
- package/src/exports/vite/utils.js +8 -10
- package/src/runtime/app/env/internal.js +4 -4
- package/src/runtime/app/forms.js +2 -2
- package/src/runtime/app/paths/client.js +3 -7
- 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 +3 -3
- package/src/runtime/app/server/remote/query.js +6 -12
- package/src/runtime/app/state/client.js +1 -2
- package/src/runtime/app/stores.js +13 -76
- package/src/runtime/client/bundle.js +1 -1
- package/src/runtime/client/client-entry.js +3 -0
- package/src/runtime/client/client.js +230 -238
- package/src/runtime/client/entry.js +24 -3
- package/src/runtime/client/payload.js +17 -0
- package/src/runtime/client/remote-functions/cache.svelte.js +3 -1
- package/src/runtime/client/remote-functions/form.svelte.js +11 -30
- package/src/runtime/client/remote-functions/prerender.svelte.js +10 -3
- package/src/runtime/client/remote-functions/query/instance.svelte.js +18 -9
- package/src/runtime/client/remote-functions/query-live/instance.svelte.js +16 -6
- package/src/runtime/client/remote-functions/shared.svelte.js +1 -2
- package/src/runtime/client/state.svelte.js +66 -49
- package/src/runtime/client/types.d.ts +3 -7
- package/src/runtime/client/utils.js +0 -96
- package/src/runtime/components/root.svelte +66 -0
- package/src/runtime/form-utils.js +16 -6
- package/src/runtime/server/cookie.js +17 -7
- package/src/runtime/server/index.js +1 -1
- package/src/runtime/server/page/index.js +7 -14
- package/src/runtime/server/page/load_data.js +1 -1
- package/src/runtime/server/page/render.js +72 -88
- package/src/runtime/server/page/server_routing.js +13 -9
- package/src/runtime/server/remote.js +23 -13
- package/src/runtime/server/respond.js +11 -8
- package/src/runtime/server/utils.js +28 -5
- package/src/runtime/telemetry/otel.js +1 -1
- package/src/runtime/types.d.ts +8 -0
- package/src/types/ambient.d.ts +5 -1
- package/src/types/global-private.d.ts +11 -18
- package/src/types/internal.d.ts +25 -30
- package/src/utils/error.js +1 -1
- package/src/utils/import.js +6 -1
- package/src/utils/mime.js +9 -0
- package/src/utils/params.js +66 -0
- package/src/utils/routing.js +90 -44
- package/src/utils/streaming.js +14 -4
- package/src/utils/url.js +0 -79
- package/src/version.js +1 -1
- package/types/index.d.ts +127 -125
- package/types/index.d.ts.map +12 -8
- package/src/core/sync/write_root.js +0 -148
- package/src/exports/internal/server.js +0 -22
- /package/src/exports/internal/{remote-functions.js → server/remote-functions.js} +0 -0
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/** @import { Span } from '@opentelemetry/api' */
|
|
2
|
+
import { try_get_request_store } from './event.js';
|
|
3
|
+
|
|
4
|
+
export function get_origin() {
|
|
5
|
+
return try_get_request_store()?.event.url.origin;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* @template {{ tracing: { enabled: boolean, root: Span, current: Span } }} T
|
|
10
|
+
* @param {T} event_like
|
|
11
|
+
* @param {Span} current
|
|
12
|
+
* @returns {T}
|
|
13
|
+
*/
|
|
14
|
+
export function merge_tracing(event_like, current) {
|
|
15
|
+
return {
|
|
16
|
+
...event_like,
|
|
17
|
+
tracing: {
|
|
18
|
+
...event_like.tracing,
|
|
19
|
+
current
|
|
20
|
+
}
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export {
|
|
25
|
+
with_request_store,
|
|
26
|
+
getRequestEvent,
|
|
27
|
+
get_request_store,
|
|
28
|
+
try_get_request_store
|
|
29
|
+
} from './event.js';
|
|
30
|
+
|
|
31
|
+
export { init_remote_functions } from './remote-functions.js';
|
|
32
|
+
|
|
33
|
+
export * from '../shared.js';
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/** @import { StandardSchemaV1 } from '@standard-schema/spec' */
|
|
2
|
+
|
|
3
|
+
export class HttpError {
|
|
4
|
+
/**
|
|
5
|
+
* @param {number} status
|
|
6
|
+
* @param {Omit<App.Error, 'status'> | string | undefined} body
|
|
7
|
+
* @param {Omit<App.Error, 'status' | 'message'>} [properties]
|
|
8
|
+
*/
|
|
9
|
+
constructor(status, body, properties) {
|
|
10
|
+
this.status = status;
|
|
11
|
+
if (typeof body === 'string') {
|
|
12
|
+
this.body = { ...properties, message: body, status };
|
|
13
|
+
} else if (body) {
|
|
14
|
+
this.body = { ...body, status };
|
|
15
|
+
} else {
|
|
16
|
+
this.body = { message: `Error: ${status}`, status };
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
toString() {
|
|
21
|
+
return JSON.stringify(this.body);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export class Redirect {
|
|
26
|
+
/**
|
|
27
|
+
* @param {300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308} status
|
|
28
|
+
* @param {string} location
|
|
29
|
+
*/
|
|
30
|
+
constructor(status, location) {
|
|
31
|
+
try {
|
|
32
|
+
new Headers({ location });
|
|
33
|
+
} catch {
|
|
34
|
+
throw new Error(
|
|
35
|
+
`Invalid redirect location ${JSON.stringify(location)}: ` +
|
|
36
|
+
'this string contains characters that cannot be used in HTTP headers'
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
this.status = status;
|
|
41
|
+
this.location = location;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* An error that was thrown from within the SvelteKit runtime that is not fatal and doesn't result in a 500, such as a 404.
|
|
47
|
+
* `SvelteKitError` goes through `handleError`.
|
|
48
|
+
* @extends Error
|
|
49
|
+
*/
|
|
50
|
+
export class SvelteKitError extends Error {
|
|
51
|
+
/**
|
|
52
|
+
* @param {number} status
|
|
53
|
+
* @param {string} text
|
|
54
|
+
* @param {string} message
|
|
55
|
+
*/
|
|
56
|
+
constructor(status, text, message) {
|
|
57
|
+
super(message);
|
|
58
|
+
this.status = status;
|
|
59
|
+
this.text = text;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* @template [T=undefined]
|
|
65
|
+
*/
|
|
66
|
+
export class ActionFailure {
|
|
67
|
+
/**
|
|
68
|
+
* @param {number} status
|
|
69
|
+
* @param {T} data
|
|
70
|
+
*/
|
|
71
|
+
constructor(status, data) {
|
|
72
|
+
this.status = status;
|
|
73
|
+
this.data = data;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Error thrown when form validation fails imperatively
|
|
79
|
+
*/
|
|
80
|
+
export class ValidationError extends Error {
|
|
81
|
+
/**
|
|
82
|
+
* @param {StandardSchemaV1.Issue[]} issues
|
|
83
|
+
*/
|
|
84
|
+
constructor(issues) {
|
|
85
|
+
super('Validation failed');
|
|
86
|
+
this.name = 'ValidationError';
|
|
87
|
+
this.issues = issues;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { createReadStream } from 'node:fs';
|
|
2
2
|
import { Readable } from 'node:stream';
|
|
3
|
-
import { SvelteKitError } from '../internal/
|
|
3
|
+
import { SvelteKitError } from '../internal/shared.js';
|
|
4
4
|
import { noop } from '../../utils/functions.js';
|
|
5
5
|
|
|
6
6
|
/** @type {WeakMap<import('http').IncomingMessage, (chunk: Buffer) => void>} */
|
|
@@ -119,11 +119,9 @@ function get_raw_body(req, body_size_limit) {
|
|
|
119
119
|
* base: string;
|
|
120
120
|
* bodySizeLimit?: number;
|
|
121
121
|
* }} options
|
|
122
|
-
* @returns {
|
|
122
|
+
* @returns {Request}
|
|
123
123
|
*/
|
|
124
|
-
|
|
125
|
-
// eslint-disable-next-line @typescript-eslint/require-await
|
|
126
|
-
export async function getRequest({ request, base, bodySizeLimit }) {
|
|
124
|
+
export function getRequest({ request, base, bodySizeLimit }) {
|
|
127
125
|
let headers = /** @type {Record<string, string>} */ (request.headers);
|
|
128
126
|
if (request.httpVersionMajor >= 2) {
|
|
129
127
|
// the Request constructor rejects headers with ':' in the name
|
|
@@ -205,11 +203,9 @@ function drain_request(res) {
|
|
|
205
203
|
/**
|
|
206
204
|
* @param {import('http').ServerResponse} res
|
|
207
205
|
* @param {Response} response
|
|
208
|
-
* @returns {
|
|
206
|
+
* @returns {void}
|
|
209
207
|
*/
|
|
210
|
-
|
|
211
|
-
// eslint-disable-next-line @typescript-eslint/require-await
|
|
212
|
-
export async function setResponse(res, response) {
|
|
208
|
+
export function setResponse(res, response) {
|
|
213
209
|
res.once('finish', () => drain_request(res));
|
|
214
210
|
res.once('close', () => drain_request(res));
|
|
215
211
|
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Define [parameter matchers](https://svelte.dev/docs/kit/advanced-routing#Matching) for your app.
|
|
3
|
+
*
|
|
4
|
+
* @example
|
|
5
|
+
* ```js
|
|
6
|
+
* import { defineParams } from '@sveltejs/kit';
|
|
7
|
+
* import * as v from 'valibot';
|
|
8
|
+
*
|
|
9
|
+
* export const params = defineParams({
|
|
10
|
+
* locale: (param) => {
|
|
11
|
+
* if (param !== 'de' && param !== 'en') return;
|
|
12
|
+
* return param;
|
|
13
|
+
* },
|
|
14
|
+
* number: v.pipe(v.string(), v.toNumber())
|
|
15
|
+
* });
|
|
16
|
+
* ```
|
|
17
|
+
*
|
|
18
|
+
* @template {Record<string, import('./public.js').ParamDefinition>} T
|
|
19
|
+
* @param {T} definitions
|
|
20
|
+
* @returns {import('./public.js').DefinedParams<T>}
|
|
21
|
+
*/
|
|
22
|
+
export function defineParams(definitions) {
|
|
23
|
+
/** @type {Record<string, import('./public.js').ParamMatcher>} */
|
|
24
|
+
const matchers = {};
|
|
25
|
+
|
|
26
|
+
for (const [key, definition] of Object.entries(definitions)) {
|
|
27
|
+
matchers[key] = normalize_param_definition(definition);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
return /** @type {import('./public.js').DefinedParams<T>} */ (matchers);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* @param {import('@sveltejs/kit').ParamDefinition} definition
|
|
35
|
+
* @returns {import('@sveltejs/kit').ParamMatcher}
|
|
36
|
+
*/
|
|
37
|
+
export function normalize_param_definition(definition) {
|
|
38
|
+
if (typeof definition === 'function') {
|
|
39
|
+
return /** @type {import('@sveltejs/kit').ParamMatcher} */ (
|
|
40
|
+
/** @type {unknown} */ ({
|
|
41
|
+
'~standard': {
|
|
42
|
+
validate(/** @type {unknown} */ value) {
|
|
43
|
+
const result = definition(/** @type {string} */ (value));
|
|
44
|
+
|
|
45
|
+
if (result === undefined) {
|
|
46
|
+
return { issues: [{ message: 'Invalid param' }] };
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
if (/** @type {any} */ (result) instanceof Promise) return result; // will be validated and rejected upstream
|
|
50
|
+
|
|
51
|
+
return { value: result };
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
})
|
|
55
|
+
);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
if (definition && typeof definition === 'object' && '~standard' in definition) {
|
|
59
|
+
return definition;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
throw new Error('Invalid param definition');
|
|
63
|
+
}
|
package/src/exports/public.d.ts
CHANGED
|
@@ -23,6 +23,7 @@ import {
|
|
|
23
23
|
import { BuildData, SSRNodeLoader, SSRRoute, ValidatedConfig } from 'types';
|
|
24
24
|
import { SvelteConfig } from '@sveltejs/vite-plugin-svelte';
|
|
25
25
|
import { StandardSchemaV1 } from '@standard-schema/spec';
|
|
26
|
+
import { Plugin } from 'vite';
|
|
26
27
|
import {
|
|
27
28
|
RouteId as AppRouteId,
|
|
28
29
|
LayoutParams as AppLayoutParams,
|
|
@@ -70,6 +71,13 @@ export interface Adapter {
|
|
|
70
71
|
* during dev, build and prerendering.
|
|
71
72
|
*/
|
|
72
73
|
emulate?: () => MaybePromise<Emulator>;
|
|
74
|
+
vite?: {
|
|
75
|
+
/**
|
|
76
|
+
* Plugins provided by the adapter are placed before any of SvelteKit's own plugins.
|
|
77
|
+
* @since 3.0.0
|
|
78
|
+
*/
|
|
79
|
+
plugins?: Plugin[];
|
|
80
|
+
};
|
|
73
81
|
}
|
|
74
82
|
|
|
75
83
|
export type LoadProperties<input extends Record<string, any> | void> = input extends void
|
|
@@ -149,7 +157,8 @@ export interface Builder {
|
|
|
149
157
|
|
|
150
158
|
/**
|
|
151
159
|
* Generate a server-side manifest to initialise the SvelteKit [server](https://svelte.dev/docs/kit/@sveltejs-kit#Server) with.
|
|
152
|
-
* @param opts
|
|
160
|
+
* @param opts
|
|
161
|
+
* @param opts.relativePath A relative path to the base directory of the server build output
|
|
153
162
|
*/
|
|
154
163
|
generateManifest: (opts: { relativePath: string; routes?: RouteDefinition[] }) => string;
|
|
155
164
|
|
|
@@ -490,32 +499,6 @@ export interface KitConfig {
|
|
|
490
499
|
};
|
|
491
500
|
/** Experimental features. Here be dragons. These are not subject to semantic versioning, so breaking changes or removal can happen in any release. */
|
|
492
501
|
experimental?: {
|
|
493
|
-
/**
|
|
494
|
-
* Options for enabling server-side [OpenTelemetry](https://opentelemetry.io/) tracing for SvelteKit operations including the [`handle` hook](https://svelte.dev/docs/kit/hooks#Server-hooks-handle), [`load` functions](https://svelte.dev/docs/kit/load), [form actions](https://svelte.dev/docs/kit/form-actions), and [remote functions](https://svelte.dev/docs/kit/remote-functions).
|
|
495
|
-
* @default { server: false, serverFile: false }
|
|
496
|
-
* @since 2.31.0
|
|
497
|
-
*/
|
|
498
|
-
tracing?: {
|
|
499
|
-
/**
|
|
500
|
-
* Enables server-side [OpenTelemetry](https://opentelemetry.io/) span emission for SvelteKit operations including the [`handle` hook](https://svelte.dev/docs/kit/hooks#Server-hooks-handle), [`load` functions](https://svelte.dev/docs/kit/load), [form actions](https://svelte.dev/docs/kit/form-actions), and [remote functions](https://svelte.dev/docs/kit/remote-functions).
|
|
501
|
-
* @default false
|
|
502
|
-
* @since 2.31.0
|
|
503
|
-
*/
|
|
504
|
-
server?: boolean;
|
|
505
|
-
};
|
|
506
|
-
|
|
507
|
-
/**
|
|
508
|
-
* @since 2.31.0
|
|
509
|
-
*/
|
|
510
|
-
instrumentation?: {
|
|
511
|
-
/**
|
|
512
|
-
* Enables `instrumentation.server.js` for tracing and observability instrumentation.
|
|
513
|
-
* @default false
|
|
514
|
-
* @since 2.31.0
|
|
515
|
-
*/
|
|
516
|
-
server?: boolean;
|
|
517
|
-
};
|
|
518
|
-
|
|
519
502
|
/**
|
|
520
503
|
* Whether to enable the experimental remote functions feature. This feature is not yet stable and may be changed or removed at any time.
|
|
521
504
|
* @default false
|
|
@@ -527,15 +510,6 @@ export interface KitConfig {
|
|
|
527
510
|
* @default false
|
|
528
511
|
*/
|
|
529
512
|
forkPreloads?: boolean;
|
|
530
|
-
|
|
531
|
-
/**
|
|
532
|
-
* Whether to enable the experimental handling of rendering errors.
|
|
533
|
-
* When enabled, `<svelte:boundary>` is used to wrap components at each level
|
|
534
|
-
* where there's an `+error.svelte`, rendering the error page if the component fails.
|
|
535
|
-
* In addition, error boundaries also work on the server and the error object goes through `handleError`.
|
|
536
|
-
* @default false
|
|
537
|
-
*/
|
|
538
|
-
handleRenderingErrors?: boolean;
|
|
539
513
|
};
|
|
540
514
|
/**
|
|
541
515
|
* Where to find various files within your project.
|
|
@@ -719,7 +693,7 @@ export interface KitConfig {
|
|
|
719
693
|
* @default undefined
|
|
720
694
|
* @since 3.0
|
|
721
695
|
*/
|
|
722
|
-
origin?:
|
|
696
|
+
origin?: string;
|
|
723
697
|
/**
|
|
724
698
|
* Whether to use relative asset paths.
|
|
725
699
|
*
|
|
@@ -904,6 +878,17 @@ export interface KitConfig {
|
|
|
904
878
|
register?: false;
|
|
905
879
|
}
|
|
906
880
|
);
|
|
881
|
+
/**
|
|
882
|
+
* Options for enabling [OpenTelemetry](https://opentelemetry.io/) tracing for SvelteKit operations.
|
|
883
|
+
* @default { server: false }
|
|
884
|
+
*/
|
|
885
|
+
tracing?: {
|
|
886
|
+
/**
|
|
887
|
+
* Enables server-side [OpenTelemetry](https://opentelemetry.io/) span emission for SvelteKit operations including the [`handle` hook](https://svelte.dev/docs/kit/hooks#Server-hooks-handle), [`load` functions](https://svelte.dev/docs/kit/load), [form actions](https://svelte.dev/docs/kit/form-actions), and [remote functions](https://svelte.dev/docs/kit/remote-functions). Tracing — and more significantly, observability instrumentation — can have a nontrivial overhead, so consider whether you really need it, or if it might be more appropriate to turn it on in development and preview environments only.
|
|
888
|
+
* @default false
|
|
889
|
+
*/
|
|
890
|
+
server?: boolean;
|
|
891
|
+
};
|
|
907
892
|
typescript?: {
|
|
908
893
|
/**
|
|
909
894
|
* A function that allows you to edit the generated `tsconfig.json`. You can mutate the config (recommended) or return a new one.
|
|
@@ -1078,7 +1063,7 @@ export type Transport = Record<string, Transporter>;
|
|
|
1078
1063
|
*/
|
|
1079
1064
|
export interface Transporter<
|
|
1080
1065
|
T = any,
|
|
1081
|
-
U =
|
|
1066
|
+
U = any /* minus falsy values, but we can't properly express that */
|
|
1082
1067
|
> {
|
|
1083
1068
|
encode: (value: T) => false | U;
|
|
1084
1069
|
decode: (data: U) => T;
|
|
@@ -1437,7 +1422,7 @@ export type AfterNavigate = (Navigation | NavigationEnter) & {
|
|
|
1437
1422
|
};
|
|
1438
1423
|
|
|
1439
1424
|
/**
|
|
1440
|
-
* The shape of the [`page`](https://svelte.dev/docs/kit/$app-state#page) reactive object
|
|
1425
|
+
* The shape of the [`page`](https://svelte.dev/docs/kit/$app-state#page) reactive object.
|
|
1441
1426
|
*/
|
|
1442
1427
|
export interface Page<
|
|
1443
1428
|
Params extends AppLayoutParams<'/'> = AppLayoutParams<'/'>,
|
|
@@ -1446,7 +1431,7 @@ export interface Page<
|
|
|
1446
1431
|
/**
|
|
1447
1432
|
* The URL of the current page.
|
|
1448
1433
|
*/
|
|
1449
|
-
url:
|
|
1434
|
+
url: ReadonlyURL & { readonly pathname: ResolvedPathname | (string & {}) };
|
|
1450
1435
|
/**
|
|
1451
1436
|
* The parameters of the current page - e.g. for a route like `/blog/[slug]`, a `{ slug: string }` object.
|
|
1452
1437
|
*/
|
|
@@ -1485,7 +1470,64 @@ export interface Page<
|
|
|
1485
1470
|
/**
|
|
1486
1471
|
* The shape of a param matcher. See [matching](https://svelte.dev/docs/kit/advanced-routing#Matching) for more info.
|
|
1487
1472
|
*/
|
|
1488
|
-
export type ParamMatcher =
|
|
1473
|
+
export type ParamMatcher<Output = any> = StandardSchemaV1<string, Output>;
|
|
1474
|
+
|
|
1475
|
+
/**
|
|
1476
|
+
* A value that can be parsed from a URL param and losslessly encoded with `String(...)`.
|
|
1477
|
+
*/
|
|
1478
|
+
export type ParamValue = string | number | boolean | bigint;
|
|
1479
|
+
|
|
1480
|
+
/**
|
|
1481
|
+
* A param matcher definition passed to [`defineParams`](https://svelte.dev/docs/kit/@sveltejs-kit#defineParams).
|
|
1482
|
+
*/
|
|
1483
|
+
export type ParamDefinition =
|
|
1484
|
+
| ((param: string) => ParamValue | undefined)
|
|
1485
|
+
| StandardSchemaV1<string, ParamValue>;
|
|
1486
|
+
|
|
1487
|
+
/**
|
|
1488
|
+
* The return type of [`defineParams`](https://svelte.dev/docs/kit/@sveltejs-kit#defineParams).
|
|
1489
|
+
*/
|
|
1490
|
+
export type DefinedParams<T extends Record<string, ParamDefinition>> = {
|
|
1491
|
+
readonly [K in keyof T]: ParamEntry<T[K]>;
|
|
1492
|
+
};
|
|
1493
|
+
|
|
1494
|
+
/**
|
|
1495
|
+
* Normalizes a property of defineParams (schema or function) to standard schema.
|
|
1496
|
+
*/
|
|
1497
|
+
type ParamEntry<M> =
|
|
1498
|
+
M extends StandardSchemaV1<any, any>
|
|
1499
|
+
? StandardSchemaV1.InferOutput<M> extends ParamValue
|
|
1500
|
+
? StandardSchemaV1<any, M>
|
|
1501
|
+
: StandardSchemaV1<any, never>
|
|
1502
|
+
: M extends (param: string) => infer R
|
|
1503
|
+
? Exclude<R, undefined> extends ParamValue
|
|
1504
|
+
? StandardSchemaV1<any, Exclude<R, undefined>>
|
|
1505
|
+
: StandardSchemaV1<any, never>
|
|
1506
|
+
: never;
|
|
1507
|
+
|
|
1508
|
+
/**
|
|
1509
|
+
* Extracts the param type from a matcher.
|
|
1510
|
+
*/
|
|
1511
|
+
export type MatcherParam<M extends StandardSchemaV1<any, any>> =
|
|
1512
|
+
M extends StandardSchemaV1<any, infer Inner>
|
|
1513
|
+
? Inner extends ParamValue
|
|
1514
|
+
? Inner
|
|
1515
|
+
: Inner extends StandardSchemaV1<any, any>
|
|
1516
|
+
? StandardSchemaV1.InferOutput<Inner> extends ParamValue
|
|
1517
|
+
? StandardSchemaV1.InferOutput<Inner>
|
|
1518
|
+
: never
|
|
1519
|
+
: never
|
|
1520
|
+
: never;
|
|
1521
|
+
|
|
1522
|
+
/**
|
|
1523
|
+
* Define [parameter matchers](https://svelte.dev/docs/kit/advanced-routing#Matching) for your app.
|
|
1524
|
+
*
|
|
1525
|
+
* @template T
|
|
1526
|
+
* @param definitions
|
|
1527
|
+
*/
|
|
1528
|
+
export function defineParams<T extends Record<string, ParamDefinition>>(
|
|
1529
|
+
definitions: T
|
|
1530
|
+
): DefinedParams<T>;
|
|
1489
1531
|
|
|
1490
1532
|
/**
|
|
1491
1533
|
* A single entry yielded by [`requested`](https://svelte.dev/docs/kit/$app-server#requested)
|
|
@@ -1692,7 +1734,9 @@ export interface ResolveOptions {
|
|
|
1692
1734
|
*/
|
|
1693
1735
|
filterSerializedResponseHeaders?: (name: string, value: string) => boolean;
|
|
1694
1736
|
/**
|
|
1695
|
-
* Determines
|
|
1737
|
+
* Determines which files should be preloaded. Files are preloaded via `<link>` tags added to the
|
|
1738
|
+
* `<head>` tag; if `output.linkHeaderPreload` is enabled, dynamically rendered pages use the
|
|
1739
|
+
* [`Link` response header](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Link) instead.
|
|
1696
1740
|
* By default, `js` and `css` files will be preloaded.
|
|
1697
1741
|
* @param input the type of the file and its path
|
|
1698
1742
|
*/
|
|
@@ -1727,19 +1771,24 @@ export interface ServerInitOptions {
|
|
|
1727
1771
|
read?: (file: string) => MaybePromise<ReadableStream | null>;
|
|
1728
1772
|
}
|
|
1729
1773
|
|
|
1774
|
+
/**
|
|
1775
|
+
* Information required to instantiate a new `Server` instance.
|
|
1776
|
+
*/
|
|
1730
1777
|
export interface SSRManifest {
|
|
1778
|
+
/** The directory where SvelteKit keeps its stuff, including static assets (such as JS and CSS) and internally-used routes. */
|
|
1731
1779
|
appDir: string;
|
|
1780
|
+
/** The `base` and `appDir` settings combined without a leading slash. */
|
|
1732
1781
|
appPath: string;
|
|
1733
1782
|
/** Static files from `config.files.assets` and the service worker (if any). */
|
|
1734
1783
|
assets: Set<string>;
|
|
1735
1784
|
mimeTypes: Record<string, string>;
|
|
1736
1785
|
|
|
1737
|
-
/** private fields */
|
|
1786
|
+
/** @internal private fields */
|
|
1738
1787
|
_: {
|
|
1739
1788
|
client: BuildData['client'];
|
|
1740
1789
|
nodes: SSRNodeLoader[];
|
|
1741
1790
|
/** hashed filename -> import to that file */
|
|
1742
|
-
remotes: Record<string, () => Promise<any>>;
|
|
1791
|
+
remotes: Record<string, () => Promise<{ default: Record<string, any> }>>;
|
|
1743
1792
|
routes: SSRRoute[];
|
|
1744
1793
|
prerendered_routes: Set<string>;
|
|
1745
1794
|
matchers: () => Promise<Record<string, ParamMatcher>>;
|
|
@@ -1930,6 +1979,14 @@ export interface Snapshot<T = any> {
|
|
|
1930
1979
|
restore: (snapshot: T) => void;
|
|
1931
1980
|
}
|
|
1932
1981
|
|
|
1982
|
+
export type ReadonlyURLSearchParams = Omit<URLSearchParams, 'set' | 'append' | 'delete' | 'sort'>;
|
|
1983
|
+
|
|
1984
|
+
export type ReadonlyURL = Readonly<
|
|
1985
|
+
Omit<URL, 'searchParams'> & {
|
|
1986
|
+
searchParams: ReadonlyURLSearchParams;
|
|
1987
|
+
}
|
|
1988
|
+
>;
|
|
1989
|
+
|
|
1933
1990
|
// If T is unknown or has an index signature, the types below will recurse indefinitely and create giant unions that TS can't handle
|
|
1934
1991
|
type WillRecurseIndefinitely<T> = unknown extends T ? true : string extends keyof T ? true : false;
|
|
1935
1992
|
|
|
@@ -2284,8 +2341,8 @@ export type RemoteQueryUpdate =
|
|
|
2284
2341
|
| RemoteQueryOverride;
|
|
2285
2342
|
|
|
2286
2343
|
export type RemoteResource<T> = Promise<T> & {
|
|
2287
|
-
/** The error in case the query fails.
|
|
2288
|
-
get error():
|
|
2344
|
+
/** The error in case the query fails. */
|
|
2345
|
+
get error(): App.Error | undefined;
|
|
2289
2346
|
/** `true` before the first result is available and during refreshes */
|
|
2290
2347
|
get loading(): boolean;
|
|
2291
2348
|
} & (
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { DEV } from 'esm-env';
|
|
2
|
+
// we use the export subpath to conditionally import the client/server `get_origin`
|
|
3
|
+
// so that `node:async_hooks` isn't pulled into the client build
|
|
4
|
+
import { get_origin } from '#internal';
|
|
5
|
+
import { matches_external_allowlist_entry } from '../utils/url.js';
|
|
6
|
+
|
|
7
|
+
// See https://datatracker.ietf.org/doc/html/rfc2606 - no domains under the .invalid TLD can be registered
|
|
8
|
+
const REDIRECT_BASE = 'https://sveltekit-redirect.invalid';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Whether a redirect location is absolute, i.e. not a root-relative or path-relative URL,
|
|
12
|
+
* and not pointing to the same origin as we're currently on (if determineable).
|
|
13
|
+
* @param {string} location
|
|
14
|
+
*/
|
|
15
|
+
export function is_external_location(location) {
|
|
16
|
+
const origin = get_origin();
|
|
17
|
+
|
|
18
|
+
try {
|
|
19
|
+
return !matches_external_allowlist_entry(location, origin ?? REDIRECT_BASE);
|
|
20
|
+
} catch {
|
|
21
|
+
return true;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* @param {string} location
|
|
27
|
+
*/
|
|
28
|
+
function is_javascript_location(location) {
|
|
29
|
+
try {
|
|
30
|
+
return new URL(location, REDIRECT_BASE).protocol === 'javascript:';
|
|
31
|
+
} catch {
|
|
32
|
+
return false;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* @param {string} location
|
|
38
|
+
* @param {{ external?: boolean | string[] }} [options]
|
|
39
|
+
*/
|
|
40
|
+
export function validate_redirect_location(location, options) {
|
|
41
|
+
if (!is_external_location(location)) return;
|
|
42
|
+
|
|
43
|
+
const external = options?.external;
|
|
44
|
+
|
|
45
|
+
if (!external) {
|
|
46
|
+
throw new Error(
|
|
47
|
+
DEV
|
|
48
|
+
? `Cannot redirect to external URL ${JSON.stringify(location)}. ` +
|
|
49
|
+
'To redirect to an external URL, pass `{ external: true }` or an allowlist of permitted origins as the third argument to `redirect`'
|
|
50
|
+
: 'Cannot redirect to external URL unless explicitly allowed'
|
|
51
|
+
);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
if (external === true) {
|
|
55
|
+
if (is_javascript_location(location)) {
|
|
56
|
+
throw new Error(
|
|
57
|
+
DEV
|
|
58
|
+
? `Cannot redirect to ${JSON.stringify(location)} with \`{ external: true }\`. ` +
|
|
59
|
+
'The `:javascript` protocol must be explicitly listed in the `external` allowlist'
|
|
60
|
+
: 'Cannot redirect to external URL unless explicitly allowed'
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
if (Array.isArray(external)) {
|
|
68
|
+
if (!external.some((allowed) => matches_external_allowlist_entry(location, allowed))) {
|
|
69
|
+
throw new Error(
|
|
70
|
+
DEV
|
|
71
|
+
? `Cannot redirect to ${JSON.stringify(location)}: URL origin is not included in the \`external\` allowlist`
|
|
72
|
+
: 'Cannot redirect to external URL unless explicitly allowed'
|
|
73
|
+
);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
throw new Error(
|
|
80
|
+
DEV
|
|
81
|
+
? '`redirect` options.external must be `true` or an array of allowed origins'
|
|
82
|
+
: 'Invalid redirect options.external value'
|
|
83
|
+
);
|
|
84
|
+
}
|
|
@@ -10,12 +10,14 @@ import { isCSSRequest, loadEnv, buildErrorMessage } from 'vite';
|
|
|
10
10
|
import { createReadableStream, getRequest, setResponse } from '../../../exports/node/index.js';
|
|
11
11
|
import { coalesce_to_error } from '../../../utils/error.js';
|
|
12
12
|
import { resolve_entry } from '../../../utils/filesystem.js';
|
|
13
|
+
import { load_and_validate_params } from '../../../utils/params.js';
|
|
13
14
|
import { from_fs, to_fs } from '../../../utils/vite.js';
|
|
14
15
|
import { posixify } from '../../../utils/os.js';
|
|
15
16
|
import { load_error_page } from '../../../core/config/index.js';
|
|
16
17
|
import { SVELTE_KIT_ASSETS } from '../../../constants.js';
|
|
17
18
|
import * as sync from '../../../core/sync/sync.js';
|
|
18
19
|
import { get_mime_lookup, get_runtime_base } from '../../../core/utils.js';
|
|
20
|
+
import '../../../utils/mime.js'; // extend mrmime with additional types (affects sirv too)
|
|
19
21
|
import { compact } from '../../../utils/array.js';
|
|
20
22
|
import { is_chrome_devtools_request, not_found } from '../utils.js';
|
|
21
23
|
import { SCHEME } from '../../../utils/url.js';
|
|
@@ -83,6 +85,10 @@ export async function dev(vite, vite_config, svelte_config, get_remotes, root) {
|
|
|
83
85
|
vite.config.logger.error(msg, { error: err });
|
|
84
86
|
}
|
|
85
87
|
|
|
88
|
+
// TODO this is inadequate — it doesn't reliably show the overlay on every page load,
|
|
89
|
+
// and when it does appear it may immediately vanish. `vite.ws.send` broadcasts
|
|
90
|
+
// to all connected clients, even ones that are unaffected by the error.
|
|
91
|
+
// we need a more considered approach
|
|
86
92
|
vite.ws.send({
|
|
87
93
|
type: 'error',
|
|
88
94
|
err: /** @type {import('vite').ErrorPayload['err']} */ ({
|
|
@@ -110,10 +116,17 @@ export async function dev(vite, vite_config, svelte_config, get_remotes, root) {
|
|
|
110
116
|
return { module, module_node, url };
|
|
111
117
|
}
|
|
112
118
|
|
|
113
|
-
function update_manifest() {
|
|
119
|
+
async function update_manifest() {
|
|
114
120
|
try {
|
|
115
121
|
({ manifest_data } = sync.create(svelte_config, root));
|
|
116
122
|
|
|
123
|
+
await load_and_validate_params({
|
|
124
|
+
routes: manifest_data.routes,
|
|
125
|
+
params_path: manifest_data.params,
|
|
126
|
+
root,
|
|
127
|
+
load: (file) => loud_ssr_load_module(file)
|
|
128
|
+
});
|
|
129
|
+
|
|
117
130
|
if (manifest_error) {
|
|
118
131
|
manifest_error = null;
|
|
119
132
|
vite.ws.send({ type: 'full-reload' });
|
|
@@ -292,22 +305,18 @@ export async function dev(vite, vite_config, svelte_config, get_remotes, root) {
|
|
|
292
305
|
})
|
|
293
306
|
),
|
|
294
307
|
matchers: async () => {
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
matchers[key] = module.match;
|
|
305
|
-
} else {
|
|
306
|
-
throw new Error(`${file} does not export a \`match\` function`);
|
|
307
|
-
}
|
|
308
|
+
if (!manifest_data.params) return {};
|
|
309
|
+
|
|
310
|
+
const url = path.resolve(root, manifest_data.params);
|
|
311
|
+
const module = await vite.ssrLoadModule(url, { fixStacktrace: true });
|
|
312
|
+
|
|
313
|
+
if (!module.params) {
|
|
314
|
+
throw new Error(
|
|
315
|
+
`${manifest_data.params} does not export \`params\` from \`defineParams\``
|
|
316
|
+
);
|
|
308
317
|
}
|
|
309
318
|
|
|
310
|
-
return
|
|
319
|
+
return module.params;
|
|
311
320
|
}
|
|
312
321
|
}
|
|
313
322
|
};
|
|
@@ -324,7 +333,9 @@ export async function dev(vite, vite_config, svelte_config, get_remotes, root) {
|
|
|
324
333
|
return error.stack?.replaceAll('\0', ''); // remove null bytes from e.g. virtual module IDs, or the response will fail
|
|
325
334
|
}
|
|
326
335
|
|
|
327
|
-
update_manifest();
|
|
336
|
+
await update_manifest();
|
|
337
|
+
|
|
338
|
+
const params_file = resolve_entry(svelte_config.kit.files.params);
|
|
328
339
|
|
|
329
340
|
/**
|
|
330
341
|
* @param {string} event
|
|
@@ -334,7 +345,7 @@ export async function dev(vite, vite_config, svelte_config, get_remotes, root) {
|
|
|
334
345
|
vite.watcher.on(event, (file) => {
|
|
335
346
|
if (
|
|
336
347
|
file.startsWith(svelte_config.kit.files.routes + path.sep) ||
|
|
337
|
-
|
|
348
|
+
(params_file && file === params_file) ||
|
|
338
349
|
svelte_config.kit.moduleExtensions.some((ext) => file.endsWith(`.remote${ext}`)) ||
|
|
339
350
|
// in contrast to server hooks, client hooks are written to the client manifest
|
|
340
351
|
// and therefore need rebuilding when they are added/removed
|
|
@@ -517,7 +528,7 @@ export async function dev(vite, vite_config, svelte_config, get_remotes, root) {
|
|
|
517
528
|
read: (file) => createReadableStream(from_fs(file))
|
|
518
529
|
});
|
|
519
530
|
|
|
520
|
-
const request =
|
|
531
|
+
const request = getRequest({
|
|
521
532
|
base,
|
|
522
533
|
request: req
|
|
523
534
|
});
|
|
@@ -568,10 +579,10 @@ export async function dev(vite, vite_config, svelte_config, get_remotes, root) {
|
|
|
568
579
|
if (rendered.status === 404) {
|
|
569
580
|
// @ts-expect-error
|
|
570
581
|
serve_static_middleware.handle(req, res, () => {
|
|
571
|
-
|
|
582
|
+
setResponse(res, rendered);
|
|
572
583
|
});
|
|
573
584
|
} else {
|
|
574
|
-
|
|
585
|
+
setResponse(res, rendered);
|
|
575
586
|
}
|
|
576
587
|
} catch (e) {
|
|
577
588
|
const error = coalesce_to_error(e);
|