@sveltejs/kit 3.0.0-next.0 → 3.0.0-next.10
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 +33 -21
- package/src/core/adapt/builder.js +29 -43
- package/src/core/adapt/index.js +1 -4
- package/src/core/config/index.js +132 -71
- package/src/core/config/options.js +294 -244
- package/src/core/config/types.d.ts +1 -1
- package/src/core/env.js +121 -5
- package/src/core/generate_manifest/index.js +12 -15
- package/src/core/postbuild/analyse.js +7 -19
- package/src/core/postbuild/crawl.js +22 -6
- package/src/core/postbuild/prerender.js +42 -23
- package/src/core/sync/create_manifest_data/index.js +53 -50
- package/src/core/sync/sync.js +0 -2
- package/src/core/sync/write_client_manifest.js +8 -15
- package/src/core/sync/write_env.js +2 -1
- package/src/core/sync/write_non_ambient.js +12 -9
- package/src/core/sync/write_server.js +13 -14
- package/src/core/sync/write_tsconfig.js +16 -8
- package/src/core/sync/write_tsconfig_test/package.json +7 -0
- package/src/core/sync/write_types/index.js +28 -24
- package/src/core/utils.js +2 -2
- package/src/exports/env/index.js +12 -0
- package/src/exports/hooks/index.js +3 -9
- package/src/exports/hooks/sequence.js +3 -2
- package/src/exports/index.js +35 -13
- package/src/exports/internal/client.js +5 -0
- package/src/exports/internal/env.js +2 -2
- package/src/exports/internal/index.js +1 -90
- 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 +62 -15
- package/src/exports/params.js +63 -0
- package/src/exports/public.d.ts +323 -170
- package/src/exports/url.js +86 -0
- package/src/exports/vite/build/build_server.js +53 -59
- package/src/exports/vite/build/remote.js +18 -11
- package/src/exports/vite/build/utils.js +0 -8
- package/src/exports/vite/dev/index.js +42 -44
- package/src/exports/vite/index.js +810 -593
- package/src/exports/vite/preview/index.js +29 -22
- package/src/exports/vite/static_analysis/index.js +2 -4
- package/src/exports/vite/static_analysis/types.d.ts +14 -0
- package/src/exports/vite/utils.js +21 -36
- package/src/runtime/app/env/internal.js +4 -4
- package/src/runtime/app/env/types.d.ts +1 -1
- package/src/runtime/app/environment/index.js +6 -0
- package/src/runtime/app/forms.js +24 -7
- package/src/runtime/app/paths/client.js +4 -10
- 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/public.d.ts +0 -28
- package/src/runtime/app/paths/server.js +9 -5
- package/src/runtime/app/server/remote/command.js +0 -3
- package/src/runtime/app/server/remote/form.js +27 -15
- package/src/runtime/app/server/remote/prerender.js +29 -36
- package/src/runtime/app/server/remote/query.js +101 -99
- package/src/runtime/app/server/remote/requested.js +22 -14
- package/src/runtime/app/server/remote/shared.js +30 -26
- 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 +411 -318
- package/src/runtime/client/entry.js +24 -3
- package/src/runtime/client/fetcher.js +3 -2
- package/src/runtime/client/ndjson.js +6 -33
- 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/command.svelte.js +7 -32
- package/src/runtime/client/remote-functions/form.svelte.js +183 -112
- package/src/runtime/client/remote-functions/prerender.svelte.js +29 -8
- package/src/runtime/client/remote-functions/query/index.js +7 -14
- package/src/runtime/client/remote-functions/query/instance.svelte.js +63 -18
- package/src/runtime/client/remote-functions/query/proxy.js +3 -3
- package/src/runtime/client/remote-functions/query-batch.svelte.js +60 -68
- package/src/runtime/client/remote-functions/query-live/instance.svelte.js +60 -18
- package/src/runtime/client/remote-functions/query-live/iterator.js +36 -55
- package/src/runtime/client/remote-functions/shared.svelte.js +88 -62
- package/src/runtime/client/sse.js +32 -0
- package/src/runtime/client/state.svelte.js +65 -49
- package/src/runtime/client/stream.js +38 -0
- package/src/runtime/client/types.d.ts +11 -7
- package/src/runtime/client/utils.js +0 -96
- 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 +100 -22
- package/src/runtime/server/cookie.js +69 -52
- package/src/runtime/server/csrf.js +65 -0
- package/src/runtime/server/data/index.js +14 -18
- package/src/runtime/server/env_module.js +0 -5
- package/src/runtime/server/index.js +2 -2
- package/src/runtime/server/page/actions.js +41 -26
- package/src/runtime/server/page/index.js +9 -15
- package/src/runtime/server/page/load_data.js +1 -1
- package/src/runtime/server/page/render.js +112 -187
- package/src/runtime/server/page/respond_with_error.js +7 -8
- package/src/runtime/server/page/server_routing.js +27 -18
- package/src/runtime/server/remote.js +355 -216
- package/src/runtime/server/respond.js +97 -61
- package/src/runtime/server/utils.js +32 -9
- package/src/runtime/shared.js +83 -13
- package/src/runtime/telemetry/otel.js +1 -1
- package/src/runtime/types.d.ts +8 -0
- package/src/types/ambient.d.ts +10 -5
- package/src/types/global-private.d.ts +15 -22
- package/src/types/internal.d.ts +89 -74
- package/src/types/private.d.ts +33 -1
- package/src/utils/error.js +24 -4
- package/src/utils/import.js +6 -1
- package/src/utils/imports.js +83 -0
- package/src/utils/mime.js +9 -0
- package/src/utils/params.js +66 -0
- package/src/utils/routing.js +90 -44
- package/src/utils/shared-iterator.js +5 -0
- package/src/utils/streaming.js +14 -4
- package/src/utils/url.js +20 -2
- package/src/version.js +1 -1
- package/types/index.d.ts +467 -537
- package/types/index.d.ts.map +22 -39
- package/src/core/sync/write_root.js +0 -148
- package/src/exports/internal/server.js +0 -22
- package/src/types/synthetic/$lib.md +0 -5
- /package/src/exports/internal/{remote-functions.js → server/remote-functions.js} +0 -0
package/src/exports/index.js
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
/** @import { StandardSchemaV1 } from '@standard-schema/spec' */
|
|
2
|
-
|
|
3
|
-
import { HttpError, Redirect, ActionFailure, ValidationError } from './internal/index.js';
|
|
2
|
+
import { HttpError, Redirect, ActionFailure, ValidationError } from './internal/shared.js';
|
|
4
3
|
import { BROWSER, DEV } from 'esm-env';
|
|
5
4
|
import {
|
|
6
5
|
add_data_suffix,
|
|
@@ -11,8 +10,10 @@ import {
|
|
|
11
10
|
strip_resolution_suffix
|
|
12
11
|
} from '../runtime/pathname.js';
|
|
13
12
|
import { text_encoder } from '../runtime/utils.js';
|
|
13
|
+
import { validate_redirect_location } from './url.js';
|
|
14
14
|
|
|
15
15
|
export { VERSION } from '../version.js';
|
|
16
|
+
export { defineParams } from './params.js';
|
|
16
17
|
|
|
17
18
|
// Keep the status codes as `number` because restricting to certain numbers makes it unnecessarily hard to use compared to the benefits
|
|
18
19
|
// (we have runtime errors already to check for invalid codes). Also see https://github.com/sveltejs/kit/issues/11780
|
|
@@ -26,10 +27,10 @@ export { VERSION } from '../version.js';
|
|
|
26
27
|
* return an error response without invoking `handleError`.
|
|
27
28
|
* Make sure you're not catching the thrown error, which would prevent SvelteKit from handling it.
|
|
28
29
|
* @param {number} status The [HTTP status code](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status#client_error_responses). Must be in the range 400-599.
|
|
29
|
-
* @param {App.Error} body An object that conforms to the App.Error type. If a string is passed, it will be used as the message property.
|
|
30
|
+
* @param {Omit<App.Error, 'status'> & { status?: App.Error['status'] }} body An object that conforms to the App.Error type. If a string is passed, it will be used as the message property.
|
|
30
31
|
* @overload
|
|
31
32
|
* @param {number} status
|
|
32
|
-
* @param {App.Error} body
|
|
33
|
+
* @param {Omit<App.Error, 'status'> & { status?: App.Error['status'] }} body
|
|
33
34
|
* @return {never}
|
|
34
35
|
* @throws {import('./public.js').HttpError} This error instructs SvelteKit to initiate HTTP error handling.
|
|
35
36
|
* @throws {Error} If the provided status is invalid (not between 400 and 599).
|
|
@@ -40,10 +41,10 @@ export { VERSION } from '../version.js';
|
|
|
40
41
|
* return an error response without invoking `handleError`.
|
|
41
42
|
* Make sure you're not catching the thrown error, which would prevent SvelteKit from handling it.
|
|
42
43
|
* @param {number} status The [HTTP status code](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status#client_error_responses). Must be in the range 400-599.
|
|
43
|
-
* @param {{ message: string } extends App.Error ?
|
|
44
|
+
* @param {{ status: number; message: string } extends App.Error ? string | void | undefined : never} body The error message.
|
|
44
45
|
* @overload
|
|
45
46
|
* @param {number} status
|
|
46
|
-
* @param {{ message: string } extends App.Error ?
|
|
47
|
+
* @param {{ status: number; message: string } extends App.Error ? string | void | undefined : never} body
|
|
47
48
|
* @return {never}
|
|
48
49
|
* @throws {import('./public.js').HttpError} This error instructs SvelteKit to initiate HTTP error handling.
|
|
49
50
|
* @throws {Error} If the provided status is invalid (not between 400 and 599).
|
|
@@ -54,17 +55,34 @@ export { VERSION } from '../version.js';
|
|
|
54
55
|
* return an error response without invoking `handleError`.
|
|
55
56
|
* Make sure you're not catching the thrown error, which would prevent SvelteKit from handling it.
|
|
56
57
|
* @param {number} status The [HTTP status code](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status#client_error_responses). Must be in the range 400-599.
|
|
57
|
-
* @param {
|
|
58
|
+
* @param {string} body The error message.
|
|
59
|
+
* @param {{ status: number; message: string } extends App.Error ? never : Omit<App.Error, 'status' | 'message'>} properties Additional properties of the App.Error type.
|
|
60
|
+
* @overload
|
|
61
|
+
* @param {number} status
|
|
62
|
+
* @param {string} body
|
|
63
|
+
* @param {{ status: number; message: string } extends App.Error ? never : Omit<App.Error, 'status' | 'message'>} properties
|
|
58
64
|
* @return {never}
|
|
59
65
|
* @throws {import('./public.js').HttpError} This error instructs SvelteKit to initiate HTTP error handling.
|
|
60
66
|
* @throws {Error} If the provided status is invalid (not between 400 and 599).
|
|
61
67
|
*/
|
|
62
|
-
|
|
68
|
+
/**
|
|
69
|
+
* Throws an error with a HTTP status code and an optional message.
|
|
70
|
+
* When called during request handling, this will cause SvelteKit to
|
|
71
|
+
* return an error response without invoking `handleError`.
|
|
72
|
+
* Make sure you're not catching the thrown error, which would prevent SvelteKit from handling it.
|
|
73
|
+
* @param {any} status The [HTTP status code](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status#client_error_responses). Must be in the range 400-599.
|
|
74
|
+
* @param {any} [body] An object that conforms to the App.Error type. If a string is passed, it will be used as the message property.
|
|
75
|
+
* @param {any} [properties] Additional properties of the App.Error type when passing a string message.
|
|
76
|
+
* @return {never}
|
|
77
|
+
* @throws {import('./public.js').HttpError} This error instructs SvelteKit to initiate HTTP error handling.
|
|
78
|
+
* @throws {Error} If the provided status is invalid (not between 400 and 599).
|
|
79
|
+
*/
|
|
80
|
+
export function error(status, body, properties) {
|
|
63
81
|
if ((!BROWSER || DEV) && (isNaN(status) || status < 400 || status > 599)) {
|
|
64
82
|
throw new Error(`HTTP error status codes must be between 400 and 599 — ${status} is invalid`);
|
|
65
83
|
}
|
|
66
84
|
|
|
67
|
-
throw new HttpError(status, body);
|
|
85
|
+
throw new HttpError(status, body, properties);
|
|
68
86
|
}
|
|
69
87
|
|
|
70
88
|
/**
|
|
@@ -92,19 +110,23 @@ export function isHttpError(e, status) {
|
|
|
92
110
|
*
|
|
93
111
|
* @param {300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | ({} & number)} status The [HTTP status code](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status#redirection_messages). Must be in the range 300-308.
|
|
94
112
|
* @param {string | URL} location The location to redirect to.
|
|
113
|
+
* @param {{ external?: boolean | string[] }} [options] To redirect to an external URL, you must pass `{ external: true }` to allow any external URL except `javascript:` URLs, or `{ external: [...] }` with an allowlist of permitted origins.
|
|
95
114
|
* @throws {import('./public.js').Redirect} This error instructs SvelteKit to redirect to the specified location.
|
|
96
|
-
* @throws {Error} If the provided status is invalid
|
|
115
|
+
* @throws {Error} If the provided status is invalid, the location cannot be used as a header value, or the location is an external URL without permission.
|
|
97
116
|
* @return {never}
|
|
98
117
|
*/
|
|
99
|
-
export function redirect(status, location) {
|
|
118
|
+
export function redirect(status, location, options) {
|
|
100
119
|
if ((!BROWSER || DEV) && (isNaN(status) || status < 300 || status > 308)) {
|
|
101
120
|
throw new Error('Invalid status code');
|
|
102
121
|
}
|
|
103
122
|
|
|
123
|
+
const href = location.toString();
|
|
124
|
+
validate_redirect_location(href, options);
|
|
125
|
+
|
|
104
126
|
throw new Redirect(
|
|
105
127
|
// @ts-ignore
|
|
106
128
|
status,
|
|
107
|
-
|
|
129
|
+
href
|
|
108
130
|
);
|
|
109
131
|
}
|
|
110
132
|
|
|
@@ -212,7 +234,7 @@ export function isActionFailure(e) {
|
|
|
212
234
|
* ```ts
|
|
213
235
|
* import { invalid } from '@sveltejs/kit';
|
|
214
236
|
* import { form } from '$app/server';
|
|
215
|
-
* import { tryLogin } from '
|
|
237
|
+
* import { tryLogin } from '#lib/server/auth';
|
|
216
238
|
* import * as v from 'valibot';
|
|
217
239
|
*
|
|
218
240
|
* export const login = form(
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/** @import { StandardSchemaV1 } from '@standard-schema/spec' */
|
|
2
2
|
/** @import { EnvVarConfig } from '@sveltejs/kit' */
|
|
3
3
|
|
|
4
|
-
import { stackless } from '
|
|
4
|
+
import { stackless } from '../../utils/error.js';
|
|
5
5
|
|
|
6
6
|
const MISSING = {
|
|
7
7
|
message: `Value is missing. If it is optional, add a Standard Schema validator declaring it as such.`
|
|
@@ -16,7 +16,7 @@ const ASYNC_VALIDATOR = {
|
|
|
16
16
|
};
|
|
17
17
|
|
|
18
18
|
/**
|
|
19
|
-
* @param {Record<string, EnvVarConfig<any
|
|
19
|
+
* @param {Record<string, EnvVarConfig<any> | undefined>} variables
|
|
20
20
|
* @param {string | undefined} value
|
|
21
21
|
* @param {string} name
|
|
22
22
|
* @param {Record<string, StandardSchemaV1.Issue[]>} issues
|
|
@@ -1,90 +1 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
export class HttpError {
|
|
4
|
-
/**
|
|
5
|
-
* @param {number} status
|
|
6
|
-
* @param {{message: string} extends App.Error ? (App.Error | string | undefined) : App.Error} body
|
|
7
|
-
*/
|
|
8
|
-
constructor(status, body) {
|
|
9
|
-
this.status = status;
|
|
10
|
-
if (typeof body === 'string') {
|
|
11
|
-
this.body = { message: body };
|
|
12
|
-
} else if (body) {
|
|
13
|
-
this.body = body;
|
|
14
|
-
} else {
|
|
15
|
-
this.body = { message: `Error: ${status}` };
|
|
16
|
-
}
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
toString() {
|
|
20
|
-
return JSON.stringify(this.body);
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
export class Redirect {
|
|
25
|
-
/**
|
|
26
|
-
* @param {300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308} status
|
|
27
|
-
* @param {string} location
|
|
28
|
-
*/
|
|
29
|
-
constructor(status, location) {
|
|
30
|
-
try {
|
|
31
|
-
new Headers({ location });
|
|
32
|
-
} catch {
|
|
33
|
-
throw new Error(
|
|
34
|
-
`Invalid redirect location ${JSON.stringify(location)}: ` +
|
|
35
|
-
'this string contains characters that cannot be used in HTTP headers'
|
|
36
|
-
);
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
this.status = status;
|
|
40
|
-
this.location = location;
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
/**
|
|
45
|
-
* 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.
|
|
46
|
-
* `SvelteKitError` goes through `handleError`.
|
|
47
|
-
* @extends Error
|
|
48
|
-
*/
|
|
49
|
-
export class SvelteKitError extends Error {
|
|
50
|
-
/**
|
|
51
|
-
* @param {number} status
|
|
52
|
-
* @param {string} text
|
|
53
|
-
* @param {string} message
|
|
54
|
-
*/
|
|
55
|
-
constructor(status, text, message) {
|
|
56
|
-
super(message);
|
|
57
|
-
this.status = status;
|
|
58
|
-
this.text = text;
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
/**
|
|
63
|
-
* @template [T=undefined]
|
|
64
|
-
*/
|
|
65
|
-
export class ActionFailure {
|
|
66
|
-
/**
|
|
67
|
-
* @param {number} status
|
|
68
|
-
* @param {T} data
|
|
69
|
-
*/
|
|
70
|
-
constructor(status, data) {
|
|
71
|
-
this.status = status;
|
|
72
|
-
this.data = data;
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
/**
|
|
77
|
-
* Error thrown when form validation fails imperatively
|
|
78
|
-
*/
|
|
79
|
-
export class ValidationError extends Error {
|
|
80
|
-
/**
|
|
81
|
-
* @param {StandardSchemaV1.Issue[]} issues
|
|
82
|
-
*/
|
|
83
|
-
constructor(issues) {
|
|
84
|
-
super('Validation failed');
|
|
85
|
-
this.name = 'ValidationError';
|
|
86
|
-
this.issues = issues;
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
export { init_remote_functions } from './remote-functions.js';
|
|
1
|
+
export * from '#internal';
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
/** @import { RequestEvent } from '@sveltejs/kit' */
|
|
2
2
|
/** @import { RequestStore } from 'types' */
|
|
3
3
|
/** @import { AsyncLocalStorage } from 'node:async_hooks' */
|
|
4
|
-
|
|
5
|
-
import { IN_WEBCONTAINER } from '../../runtime/server/constants.js';
|
|
4
|
+
import { IN_WEBCONTAINER } from '../../../runtime/server/constants.js';
|
|
6
5
|
|
|
7
6
|
/** @type {RequestStore | null} */
|
|
8
7
|
let sync_store = null;
|
|
@@ -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,8 +1,11 @@
|
|
|
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
|
+
/** @type {WeakMap<import('http').IncomingMessage, (chunk: Buffer) => void>} */
|
|
7
|
+
const body_data_listeners = new WeakMap();
|
|
8
|
+
|
|
6
9
|
/**
|
|
7
10
|
* @param {import('http').IncomingMessage} req
|
|
8
11
|
* @param {number} [body_size_limit]
|
|
@@ -47,17 +50,19 @@ function get_raw_body(req, body_size_limit) {
|
|
|
47
50
|
return;
|
|
48
51
|
}
|
|
49
52
|
|
|
50
|
-
|
|
53
|
+
/** @param {Error} error */
|
|
54
|
+
const on_error = (error) => {
|
|
51
55
|
cancelled = true;
|
|
52
56
|
controller.error(error);
|
|
53
|
-
}
|
|
57
|
+
};
|
|
54
58
|
|
|
55
|
-
|
|
59
|
+
const on_end = () => {
|
|
56
60
|
if (cancelled) return;
|
|
57
61
|
controller.close();
|
|
58
|
-
}
|
|
62
|
+
};
|
|
59
63
|
|
|
60
|
-
|
|
64
|
+
/** @param {Buffer} chunk */
|
|
65
|
+
const on_data = (chunk) => {
|
|
61
66
|
if (cancelled) return;
|
|
62
67
|
|
|
63
68
|
size += chunk.length;
|
|
@@ -89,7 +94,12 @@ function get_raw_body(req, body_size_limit) {
|
|
|
89
94
|
if (controller.desiredSize === null || controller.desiredSize <= 0) {
|
|
90
95
|
req.pause();
|
|
91
96
|
}
|
|
92
|
-
}
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
req.on('error', on_error);
|
|
100
|
+
req.on('end', on_end);
|
|
101
|
+
req.on('data', on_data);
|
|
102
|
+
body_data_listeners.set(req, on_data);
|
|
93
103
|
},
|
|
94
104
|
|
|
95
105
|
pull() {
|
|
@@ -109,11 +119,9 @@ function get_raw_body(req, body_size_limit) {
|
|
|
109
119
|
* base: string;
|
|
110
120
|
* bodySizeLimit?: number;
|
|
111
121
|
* }} options
|
|
112
|
-
* @returns {
|
|
122
|
+
* @returns {Request}
|
|
113
123
|
*/
|
|
114
|
-
|
|
115
|
-
// eslint-disable-next-line @typescript-eslint/require-await
|
|
116
|
-
export async function getRequest({ request, base, bodySizeLimit }) {
|
|
124
|
+
export function getRequest({ request, base, bodySizeLimit }) {
|
|
117
125
|
let headers = /** @type {Record<string, string>} */ (request.headers);
|
|
118
126
|
if (request.httpVersionMajor >= 2) {
|
|
119
127
|
// the Request constructor rejects headers with ':' in the name
|
|
@@ -154,14 +162,53 @@ export async function getRequest({ request, base, bodySizeLimit }) {
|
|
|
154
162
|
});
|
|
155
163
|
}
|
|
156
164
|
|
|
165
|
+
/**
|
|
166
|
+
* Drains any unconsumed request body once the response has been sent. When a
|
|
167
|
+
* route doesn't read the request body (for example a page route receiving a
|
|
168
|
+
* POST), the unread bytes remain buffered in the socket. On keep-alive
|
|
169
|
+
* connections Node's HTTP parser then reads those leftover bytes as the next
|
|
170
|
+
* request, fails to parse them, and resets the connection — losing any
|
|
171
|
+
* pipelined request. Resuming the request discards the bytes so the connection
|
|
172
|
+
* stays usable.
|
|
173
|
+
*
|
|
174
|
+
* Because `get_raw_body` attaches a `data` listener, Node marks the request as
|
|
175
|
+
* being consumed (`req._consuming`) and skips its own automatic drain, so we
|
|
176
|
+
* have to do it ourselves. The whole remaining body is read and discarded; this
|
|
177
|
+
* is the intended trade-off (keeping the connection reusable) over destroying it.
|
|
178
|
+
* @see https://github.com/sveltejs/kit/issues/14916
|
|
179
|
+
* @see https://github.com/sveltejs/kit/issues/15526
|
|
180
|
+
* @param {import('http').ServerResponse} res
|
|
181
|
+
*/
|
|
182
|
+
function drain_request(res) {
|
|
183
|
+
const req = res.req;
|
|
184
|
+
if (!req || req.readableEnded || req.destroyed) return;
|
|
185
|
+
|
|
186
|
+
// When the body went unread, get_raw_body's `data` listener is still attached
|
|
187
|
+
// and enqueues into a ReadableStream nobody consumes; it pauses the request at
|
|
188
|
+
// the high water mark, so one chunk sits in memory and the rest stays buffered
|
|
189
|
+
// in the socket. Remove only that `data` listener so the resumed stream drops
|
|
190
|
+
// the remaining bytes instead of re-buffering them. The `end` and `error`
|
|
191
|
+
// listeners stay attached so the body's ReadableStream is still closed (or
|
|
192
|
+
// errored) once draining completes, and a consumer that stopped reading
|
|
193
|
+
// mid-body sees a clean end instead of hanging.
|
|
194
|
+
const on_data = body_data_listeners.get(req);
|
|
195
|
+
if (on_data) {
|
|
196
|
+
req.removeListener('data', on_data);
|
|
197
|
+
body_data_listeners.delete(req);
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
req.resume();
|
|
201
|
+
}
|
|
202
|
+
|
|
157
203
|
/**
|
|
158
204
|
* @param {import('http').ServerResponse} res
|
|
159
205
|
* @param {Response} response
|
|
160
|
-
* @returns {
|
|
206
|
+
* @returns {void}
|
|
161
207
|
*/
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
208
|
+
export function setResponse(res, response) {
|
|
209
|
+
res.once('finish', () => drain_request(res));
|
|
210
|
+
res.once('close', () => drain_request(res));
|
|
211
|
+
|
|
165
212
|
for (const [key, value] of response.headers) {
|
|
166
213
|
try {
|
|
167
214
|
res.setHeader(key, key === 'set-cookie' ? response.headers.getSetCookie() : value);
|
|
@@ -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
|
+
}
|