@sveltejs/kit 3.0.0-next.2 → 3.0.0-next.21
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 +62 -36
- package/src/cli.js +15 -12
- package/src/constants.js +6 -1
- package/src/core/adapt/builder.js +66 -72
- package/src/core/adapt/index.js +17 -6
- package/src/core/config/index.js +134 -80
- package/src/core/config/options.js +295 -273
- package/src/core/config/types.d.ts +1 -1
- package/src/core/env.js +146 -16
- package/src/core/generate_manifest/index.js +18 -15
- package/src/core/postbuild/analyse.js +8 -20
- package/src/core/postbuild/crawl.js +22 -6
- package/src/core/postbuild/entities.js +8 -2
- package/src/core/postbuild/fallback.js +4 -2
- package/src/core/postbuild/prerender.js +222 -70
- package/src/core/postbuild/queue.js +2 -1
- package/src/core/sync/create_manifest_data/conflict.js +1 -1
- package/src/core/sync/create_manifest_data/index.js +82 -62
- package/src/core/sync/sync.js +40 -31
- package/src/core/sync/ts.js +1 -1
- package/src/core/sync/utils.js +22 -2
- package/src/core/sync/{write_non_ambient.js → write_app_types.js} +107 -58
- package/src/core/sync/write_client_manifest.js +14 -29
- package/src/core/sync/write_env.js +7 -5
- package/src/core/sync/write_server.js +37 -45
- package/src/core/sync/write_tsconfig/index.js +274 -0
- package/src/core/sync/write_tsconfig/test-app/package.json +7 -0
- package/src/core/sync/write_tsconfig/utils.js +77 -0
- package/src/core/sync/write_tsconfig/validate.js +128 -0
- package/src/core/sync/write_types/index.js +127 -123
- package/src/core/utils.js +30 -5
- package/src/exports/env/index.js +77 -0
- package/src/exports/env/public.d.ts +55 -0
- package/src/exports/hooks/index.js +3 -9
- package/src/exports/hooks/public.d.ts +195 -0
- package/src/exports/hooks/sequence.js +9 -6
- package/src/exports/index.js +52 -29
- package/src/exports/internal/client.js +5 -0
- package/src/exports/internal/env.js +8 -5
- package/src/exports/internal/index.js +1 -90
- package/src/exports/internal/{event.js → server/event.js} +2 -3
- package/src/exports/internal/server/index.js +37 -0
- package/src/exports/internal/server/telemetry.js +95 -0
- package/src/exports/internal/shared.js +90 -0
- package/src/exports/node/index.js +64 -22
- package/src/exports/params/index.js +70 -0
- package/src/exports/params/public.d.ts +63 -0
- package/src/exports/public.d.ts +50 -1733
- package/src/exports/remote/index.js +11 -0
- package/src/exports/remote/public.d.ts +519 -0
- package/src/exports/url.js +86 -0
- package/src/exports/vite/build/build_server.js +54 -65
- package/src/exports/vite/build/remote.js +24 -19
- package/src/exports/vite/build/utils.js +0 -8
- package/src/exports/vite/dev/index.js +218 -146
- package/src/exports/vite/index.js +1590 -858
- package/src/exports/vite/module_ids.js +2 -2
- package/src/exports/vite/preview/index.js +40 -32
- package/src/exports/vite/public.d.ts +588 -0
- package/src/exports/vite/utils.js +84 -46
- package/src/pathname.js +55 -0
- package/src/runner.js +15 -0
- 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 +3 -3
- package/src/runtime/app/{forms.js → forms/index.js} +73 -42
- package/src/runtime/app/forms/public.d.ts +2 -0
- package/src/runtime/app/forms/types.d.ts +56 -0
- package/src/runtime/app/internal/transport.js +53 -0
- package/src/runtime/app/manifest/index.js +1 -0
- package/src/runtime/app/{navigation.js → navigation/index.js} +2 -1
- package/src/runtime/app/navigation/public.d.ts +237 -0
- package/src/runtime/app/paths/client.js +37 -37
- package/src/runtime/app/paths/index.js +1 -1
- package/src/runtime/app/paths/internal/client.js +34 -2
- package/src/runtime/app/paths/internal/server.js +6 -23
- package/src/runtime/app/paths/internal.d.ts +3 -0
- package/src/runtime/app/paths/public.d.ts +1 -29
- package/src/runtime/app/paths/server.js +36 -17
- package/src/runtime/app/paths/types.d.ts +11 -19
- package/src/runtime/app/server/index.js +2 -2
- package/src/runtime/app/server/public.d.ts +201 -0
- package/src/runtime/app/server/remote/command.js +13 -11
- package/src/runtime/app/server/remote/form.js +61 -39
- package/src/runtime/app/server/remote/prerender.js +45 -45
- package/src/runtime/app/server/remote/query.js +106 -108
- package/src/runtime/app/server/remote/requested.js +27 -19
- package/src/runtime/app/server/remote/shared.js +76 -76
- package/src/runtime/app/service-worker/index.js +24 -0
- package/src/runtime/app/state/client.js +4 -2
- package/src/runtime/app/state/index.js +7 -5
- package/src/runtime/app/state/public.d.ts +72 -0
- package/src/runtime/app/state/server.js +3 -0
- package/src/runtime/app/stores.js +15 -78
- package/src/runtime/client/bundle.js +1 -1
- package/src/runtime/client/client-entry.js +3 -0
- package/src/runtime/client/client.js +1336 -648
- package/src/runtime/client/constants.js +3 -6
- package/src/runtime/client/entry.js +24 -3
- package/src/runtime/client/fetcher.js +25 -25
- package/src/runtime/client/ndjson.js +1 -1
- package/src/runtime/client/parse.js +1 -1
- 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 +37 -61
- package/src/runtime/client/remote-functions/form.svelte.js +267 -178
- package/src/runtime/client/remote-functions/prerender.svelte.js +32 -11
- package/src/runtime/client/remote-functions/query/index.js +10 -17
- package/src/runtime/client/remote-functions/query/instance.svelte.js +64 -18
- package/src/runtime/client/remote-functions/query/proxy.js +5 -5
- package/src/runtime/client/remote-functions/query-batch.svelte.js +61 -70
- package/src/runtime/client/remote-functions/query-live/index.js +1 -1
- package/src/runtime/client/remote-functions/query-live/instance.svelte.js +63 -21
- package/src/runtime/client/remote-functions/query-live/iterator.js +15 -12
- package/src/runtime/client/remote-functions/query-live/proxy.js +2 -12
- package/src/runtime/client/remote-functions/shared.svelte.js +90 -65
- package/src/runtime/client/snapshots.js +147 -0
- package/src/runtime/client/state.svelte.js +94 -55
- package/src/runtime/client/stream.js +3 -2
- package/src/runtime/client/types.d.ts +13 -9
- package/src/runtime/client/utils.js +22 -110
- package/src/runtime/components/root.svelte +56 -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 +172 -61
- package/src/runtime/pathname.js +20 -32
- package/src/runtime/props.svelte.js +72 -0
- package/src/runtime/server/constants.js +0 -3
- package/src/runtime/server/cookie.js +72 -55
- package/src/runtime/server/csrf.js +65 -0
- package/src/runtime/server/data/index.js +49 -53
- package/src/runtime/server/dev.js +22 -0
- package/src/runtime/server/endpoint.js +6 -7
- package/src/runtime/server/env_module.js +0 -5
- package/src/runtime/server/errors.js +160 -0
- package/src/runtime/server/fetch.js +32 -39
- package/src/runtime/server/index.js +90 -64
- package/src/runtime/server/internal.js +71 -0
- package/src/runtime/server/page/actions.js +85 -64
- package/src/runtime/server/page/crypto.js +2 -2
- package/src/runtime/server/page/csp.js +88 -104
- package/src/runtime/server/page/data_serializer.js +24 -25
- package/src/runtime/server/page/index.js +36 -53
- package/src/runtime/server/page/load_data.js +50 -57
- package/src/runtime/server/page/render.js +173 -239
- package/src/runtime/server/page/respond_with_error.js +17 -31
- package/src/runtime/server/page/serialize_data.js +2 -13
- package/src/runtime/server/page/server_routing.js +85 -26
- package/src/runtime/server/remote-functions.js +640 -0
- package/src/runtime/server/respond.js +190 -131
- package/src/runtime/server/sourcemaps.js +183 -0
- package/src/runtime/server/state.js +53 -0
- package/src/runtime/server/utils.js +13 -155
- package/src/runtime/shared.js +20 -40
- package/src/runtime/utils.js +3 -0
- package/src/types/ambient-private.d.ts +11 -1
- package/src/types/ambient.d.ts +87 -36
- package/src/types/global-private.d.ts +25 -25
- package/src/types/internal.d.ts +163 -157
- package/src/types/private.d.ts +41 -1
- package/src/utils/error.js +28 -4
- package/src/utils/escape.js +9 -25
- package/src/utils/features.js +1 -1
- package/src/utils/filesystem.js +1 -23
- package/src/utils/fork.js +7 -2
- package/src/utils/hash.js +21 -0
- package/src/utils/http.js +8 -7
- package/src/utils/import.js +9 -2
- package/src/utils/imports.js +83 -0
- package/src/utils/mime.js +9 -0
- package/src/utils/page_nodes.js +6 -7
- package/src/utils/params.js +67 -0
- package/src/utils/regex.js +9 -0
- package/src/utils/routing.js +145 -73
- package/src/utils/shared-iterator.js +5 -0
- package/src/utils/streaming.js +14 -4
- package/src/utils/url.js +33 -2
- package/src/version.js +1 -1
- package/types/index.d.ts +2616 -2433
- package/types/index.d.ts.map +120 -106
- package/src/core/sync/write_ambient.js +0 -18
- package/src/core/sync/write_root.js +0 -148
- package/src/core/sync/write_tsconfig.js +0 -250
- package/src/exports/internal/server.js +0 -22
- package/src/exports/node/polyfills.js +0 -30
- package/src/runtime/server/app.js +0 -9
- package/src/runtime/server/remote.js +0 -457
- package/src/runtime/shared-server.js +0 -7
- package/src/runtime/telemetry/otel.js +0 -21
- package/src/runtime/telemetry/record_span.js +0 -65
- package/src/types/synthetic/$lib.md +0 -5
- /package/src/exports/internal/{remote-functions.js → server/remote-functions.js} +0 -0
- /package/src/{runtime/telemetry/noop.js → telemetry.js} +0 -0
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
import { RouteId as AppRouteId, LayoutParams as AppLayoutParams } from '$app/types';
|
|
2
|
+
|
|
3
|
+
export * from './index.js';
|
|
4
|
+
|
|
5
|
+
// @ts-ignore this is an optional peer dependency so could be missing. Written like this so dts-buddy preserves the ts-ignore
|
|
6
|
+
type Span = import('@opentelemetry/api').Span;
|
|
7
|
+
|
|
8
|
+
export interface Cookies {
|
|
9
|
+
/**
|
|
10
|
+
* Gets a cookie that was previously set with `cookies.set`, or from the request headers.
|
|
11
|
+
* @param name the name of the cookie
|
|
12
|
+
* @param opts the options, passed directly to `cookie.parseCookie`. See documentation [here](https://github.com/jshttp/cookie?tab=readme-ov-file#cookieparsecookiestr-options)
|
|
13
|
+
*/
|
|
14
|
+
get: (name: string, opts?: import('cookie').ParseOptions) => string | undefined;
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Gets all cookies that were previously set with `cookies.set`, or from the request headers.
|
|
18
|
+
* @param opts the options, passed directly to `cookie.parseCookie`. See documentation [here](https://github.com/jshttp/cookie?tab=readme-ov-file#cookieparsecookiestr-options)
|
|
19
|
+
*/
|
|
20
|
+
getAll: (opts?: import('cookie').ParseOptions) => Array<{ name: string; value: string }>;
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Sets a cookie. This will add a `set-cookie` header to the response, but also make the cookie available via `cookies.get` or `cookies.getAll` during the current request.
|
|
24
|
+
*
|
|
25
|
+
* The `httpOnly` is `true` by default, as is `secure`, except during development, when it defaults to `false`. These must be explicitly disabled if you want cookies to be readable by client-side JavaScript and/or transmitted over HTTP.
|
|
26
|
+
*
|
|
27
|
+
* The `path` option is `'/'` by default. You can use relative paths, or set `path: ''` to make the cookie only available on the current path and its children.
|
|
28
|
+
* @param name the name of the cookie
|
|
29
|
+
* @param value the cookie value
|
|
30
|
+
* @param opts the options passed to `cookie.stringifySetCookie` with the SvelteKit defaults described above. See documentation [here](https://github.com/jshttp/cookie?tab=readme-ov-file#cookiestringifysetcookiesetcookieobj-options)
|
|
31
|
+
*/
|
|
32
|
+
set: (name: string, value: string, opts: import('cookie').SerializeOptions) => void;
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Deletes a cookie by setting its value to an empty string and setting the expiry date in the past.
|
|
36
|
+
*
|
|
37
|
+
* The `httpOnly` is `true` by default, as is `secure`, except during development, when it defaults to `false`. These must be explicitly disabled if you want cookies to be readable by client-side JavaScript and/or transmitted over HTTP.
|
|
38
|
+
*
|
|
39
|
+
* The `path` option is `'/'` by default. You can use relative paths, or set `path: ''` to make the cookie only available on the current path and its children.
|
|
40
|
+
* @param name the name of the cookie
|
|
41
|
+
* @param opts the options passed to `cookie.stringifySetCookie` with the SvelteKit defaults described above. See documentation [here](https://github.com/jshttp/cookie?tab=readme-ov-file#cookiestringifysetcookiesetcookieobj-options)
|
|
42
|
+
*/
|
|
43
|
+
delete: (name: string, opts: import('cookie').SerializeOptions) => void;
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Parses a single `Set-Cookie` header. This allows you to apply cookies received from an external source:
|
|
47
|
+
*
|
|
48
|
+
* ```js
|
|
49
|
+
* import { getRequestEvent } from '$app/server';
|
|
50
|
+
*
|
|
51
|
+
* export async function GET() {
|
|
52
|
+
* const { cookies } = getRequestEvent();
|
|
53
|
+
*
|
|
54
|
+
* const response = await fetch('...');
|
|
55
|
+
*
|
|
56
|
+
* for (const str of response.headers.getSetCookie()) {
|
|
57
|
+
* const { name, value, ...options } = cookies.parse(str);
|
|
58
|
+
* cookies.set(name, value, { ...options, path: '/' });
|
|
59
|
+
* }
|
|
60
|
+
*
|
|
61
|
+
* // ...
|
|
62
|
+
* }
|
|
63
|
+
* ```
|
|
64
|
+
*
|
|
65
|
+
* Note the use of `headers.getSetCookie()`, which returns an array of cookie headers, _not_ `headers.get('set-cookie')` which returns a single comma-separated string.
|
|
66
|
+
*/
|
|
67
|
+
parse: typeof import('cookie').parseSetCookie;
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Serialize a cookie name-value pair into a `Set-Cookie` header string, but don't apply it to the response.
|
|
71
|
+
*
|
|
72
|
+
* The `httpOnly` is `true` by default, as is `secure`, except during development, when it defaults to `false`. These must be explicitly disabled if you want cookies to be readable by client-side JavaScript and/or transmitted over HTTP.
|
|
73
|
+
*
|
|
74
|
+
* The `path` option is `'/'` by default. You can use relative paths, or set `path: ''` to make the cookie only available on the current path and its children.
|
|
75
|
+
* @param name the name of the cookie
|
|
76
|
+
* @param value the cookie value
|
|
77
|
+
* @param opts the options passed to `cookie.stringifySetCookie` with the SvelteKit defaults described above. See documentation [here](https://github.com/jshttp/cookie?tab=readme-ov-file#cookiestringifysetcookiesetcookieobj-options)
|
|
78
|
+
*/
|
|
79
|
+
serialize: (name: string, value: string, opts: import('cookie').SerializeOptions) => string;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export interface RequestEvent<
|
|
83
|
+
Params extends AppLayoutParams<'/'> = AppLayoutParams<'/'>,
|
|
84
|
+
RouteId extends AppRouteId | null = AppRouteId | null
|
|
85
|
+
> {
|
|
86
|
+
/**
|
|
87
|
+
* Get or set cookies related to the current request
|
|
88
|
+
*/
|
|
89
|
+
readonly cookies: Cookies;
|
|
90
|
+
/**
|
|
91
|
+
* `fetch` is equivalent to the [native `fetch` web API](https://developer.mozilla.org/en-US/docs/Web/API/fetch), with a few additional features:
|
|
92
|
+
*
|
|
93
|
+
* - It can be used to make credentialed requests on the server, as it inherits the `cookie` and `authorization` headers for the page request.
|
|
94
|
+
* - It can make relative requests on the server (ordinarily, `fetch` requires a URL with an origin when used in a server context).
|
|
95
|
+
* - Internal requests (e.g. for `+server.js` routes) go directly to the handler function when running on the server, without the overhead of an HTTP call.
|
|
96
|
+
* - During server-side rendering, the response will be captured and inlined into the rendered HTML by hooking into the `text` and `json` methods of the `Response` object. Note that headers will _not_ be serialized, unless explicitly included via [`filterSerializedResponseHeaders`](https://svelte.dev/docs/kit/hooks#handle)
|
|
97
|
+
* - During hydration, the response will be read from the HTML, guaranteeing consistency and preventing an additional network request.
|
|
98
|
+
*
|
|
99
|
+
* You can learn more about making credentialed requests with cookies [here](https://svelte.dev/docs/kit/load#Cookies).
|
|
100
|
+
*/
|
|
101
|
+
readonly fetch: typeof fetch;
|
|
102
|
+
/**
|
|
103
|
+
* The client's IP address, set by the adapter.
|
|
104
|
+
*/
|
|
105
|
+
readonly getClientAddress: () => string;
|
|
106
|
+
/**
|
|
107
|
+
* Contains custom data that was added to the request within the [`server handle hook`](https://svelte.dev/docs/kit/hooks#handle).
|
|
108
|
+
*/
|
|
109
|
+
readonly locals: App.Locals;
|
|
110
|
+
/**
|
|
111
|
+
* The parameters of the current route - e.g. for a route like `/blog/[slug]`, a `{ slug: string }` object.
|
|
112
|
+
*
|
|
113
|
+
* Inside `query` functions (including `query.batch` and `query.live`), accessing this property throws an error.
|
|
114
|
+
* Pass values from the page as arguments to the query instead. Inside `form` and `command` functions it relates to the page
|
|
115
|
+
* the remote function was called from, _not_ the URL of the endpoint SvelteKit creates for the remote function. Never use it
|
|
116
|
+
* to determine whether or not a user is authorized to access certain data, as these values are part of the request which could be manipulated.
|
|
117
|
+
*/
|
|
118
|
+
readonly params: Params;
|
|
119
|
+
/**
|
|
120
|
+
* Additional data made available through the adapter.
|
|
121
|
+
*/
|
|
122
|
+
readonly platform: Readonly<App.Platform> | undefined;
|
|
123
|
+
/**
|
|
124
|
+
* The original request object.
|
|
125
|
+
*/
|
|
126
|
+
readonly request: Request;
|
|
127
|
+
/**
|
|
128
|
+
* Info about the current route.
|
|
129
|
+
*/
|
|
130
|
+
readonly route: {
|
|
131
|
+
/**
|
|
132
|
+
* The ID of the current route - e.g. for `src/routes/blog/[slug]`, it would be `/blog/[slug]`. It is `null` when no route is matched.
|
|
133
|
+
*
|
|
134
|
+
* Inside `query` functions (including `query.batch` and `query.live`), accessing this property throws an error.
|
|
135
|
+
* Pass values from the page as arguments to the query instead. Inside `form` and `command` functions it relates to the page
|
|
136
|
+
* the remote function was called from, _not_ the URL of the endpoint SvelteKit creates for the remote function. Never use it
|
|
137
|
+
* to determine whether or not a user is authorized to access certain data, as these values are part of the request which could be manipulated.
|
|
138
|
+
*/
|
|
139
|
+
id: RouteId;
|
|
140
|
+
};
|
|
141
|
+
/**
|
|
142
|
+
* If you need to set headers for the response, you can do so using the this method. This is useful if you want the page to be cached, for example:
|
|
143
|
+
*
|
|
144
|
+
* ```js
|
|
145
|
+
* /// file: src/routes/blog/+page.js
|
|
146
|
+
* export async function load({ fetch, setHeaders }) {
|
|
147
|
+
* const url = `https://cms.example.com/articles.json`;
|
|
148
|
+
* const response = await fetch(url);
|
|
149
|
+
*
|
|
150
|
+
* setHeaders({
|
|
151
|
+
* age: response.headers.get('age'),
|
|
152
|
+
* 'cache-control': response.headers.get('cache-control')
|
|
153
|
+
* });
|
|
154
|
+
*
|
|
155
|
+
* return response.json();
|
|
156
|
+
* }
|
|
157
|
+
* ```
|
|
158
|
+
*
|
|
159
|
+
* Setting the same header multiple times (even in separate `load` functions) is an error — you can only set a given header once.
|
|
160
|
+
*
|
|
161
|
+
* You cannot add a `set-cookie` header with `setHeaders` — use the [`cookies`](https://svelte.dev/docs/kit/$app-server#Cookies) API instead.
|
|
162
|
+
*/
|
|
163
|
+
readonly setHeaders: (headers: Record<string, string>) => void;
|
|
164
|
+
/**
|
|
165
|
+
* The requested URL.
|
|
166
|
+
*
|
|
167
|
+
* Inside `query` functions (including `query.batch` and `query.live`), accessing this property throws an error.
|
|
168
|
+
* Pass values from the page as arguments to the query instead. Inside `form` and `command` functions it relates to the page
|
|
169
|
+
* the remote function was called from, _not_ the URL of the endpoint SvelteKit creates for the remote function. Never use it
|
|
170
|
+
* to determine whether or not a user is authorized to access certain data, as these values are part of the request which could be manipulated.
|
|
171
|
+
*/
|
|
172
|
+
readonly url: URL;
|
|
173
|
+
/**
|
|
174
|
+
* `true` if the request comes from the client asking for `+page/layout.server.js` data. The `url` property will be stripped of the internal information
|
|
175
|
+
* related to the data request in this case. Use this property instead if the distinction is important to you.
|
|
176
|
+
*/
|
|
177
|
+
readonly isDataRequest: boolean;
|
|
178
|
+
/**
|
|
179
|
+
* `true` for `+server.js` calls coming from SvelteKit without the overhead of actually making an HTTP request. This happens when you make same-origin `fetch` requests on the server.
|
|
180
|
+
*/
|
|
181
|
+
readonly isSubRequest: boolean;
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* Access to spans for tracing. If tracing is not enabled, these spans will do nothing.
|
|
185
|
+
* @since 2.31.0
|
|
186
|
+
*/
|
|
187
|
+
readonly tracing: {
|
|
188
|
+
/** Whether tracing is enabled. */
|
|
189
|
+
enabled: boolean;
|
|
190
|
+
/** The root span for the request. This span is named `sveltekit.handle.root`. */
|
|
191
|
+
root: Span;
|
|
192
|
+
/** The span associated with the current `handle` hook, `load` function, or form action. */
|
|
193
|
+
current: Span;
|
|
194
|
+
};
|
|
195
|
+
|
|
196
|
+
/**
|
|
197
|
+
* `true` if the request comes from the client via a remote function. The `url` property will be stripped of the internal information
|
|
198
|
+
* related to the data request in this case. Use this property instead if the distinction is important to you.
|
|
199
|
+
*/
|
|
200
|
+
readonly isRemoteRequest: boolean;
|
|
201
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/** @import { RemoteCommand } from '@sveltejs/kit' */
|
|
1
|
+
/** @import { RemoteCommand } from '@sveltejs/kit/remote' */
|
|
2
2
|
/** @import { MaybePromise, RemoteCommandInternals } from 'types' */
|
|
3
3
|
/** @import { StandardSchemaV1 } from '@standard-schema/spec' */
|
|
4
4
|
import { get_request_store } from '@sveltejs/kit/internal/server';
|
|
@@ -65,21 +65,23 @@ export function command(validate_or_fn, maybe_fn) {
|
|
|
65
65
|
const wrapper = (arg) => {
|
|
66
66
|
const { event, state } = get_request_store();
|
|
67
67
|
|
|
68
|
-
if (
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
68
|
+
if (
|
|
69
|
+
!MUTATIVE_METHODS.includes(event.request.method) ||
|
|
70
|
+
state.is_in_remote_query ||
|
|
71
|
+
state.is_in_remote_prerender
|
|
72
|
+
) {
|
|
73
|
+
const violation =
|
|
74
|
+
state.is_in_remote_query || state.is_in_remote_prerender
|
|
75
|
+
? `inside a query or prerender function`
|
|
76
|
+
: `from a ${event.request.method} handler`;
|
|
77
|
+
|
|
78
|
+
throw new Error(`Cannot call a command (${__.name}) ${violation}`);
|
|
72
79
|
}
|
|
73
80
|
|
|
74
81
|
if (state.is_in_render) {
|
|
75
|
-
throw new Error(
|
|
76
|
-
`Cannot call a command (\`${__.name}(${maybe_fn ? '...' : ''})\`) during server-side rendering`
|
|
77
|
-
);
|
|
82
|
+
throw new Error(`Cannot call a command (${__.name}) during server-side rendering`);
|
|
78
83
|
}
|
|
79
84
|
|
|
80
|
-
state.remote.refreshes ??= new Map();
|
|
81
|
-
state.remote.reconnects ??= new Map();
|
|
82
|
-
|
|
83
85
|
const promise = Promise.resolve(
|
|
84
86
|
run_remote_function(event, state, true, () => validate(arg), fn)
|
|
85
87
|
);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
/** @import { RemoteFormInput, RemoteForm, InvalidField } from '@sveltejs/kit' */
|
|
2
|
-
/** @import { InternalRemoteFormIssue, MaybePromise, RemoteFormInternals } from 'types' */
|
|
1
|
+
/** @import { RemoteFormInput, RemoteForm, InvalidField } from '@sveltejs/kit/remote' */
|
|
2
|
+
/** @import { InternalRemoteFormIssue, MaybePromise, HasNonOptionalBoolean, RemoteFormInternals } from 'types' */
|
|
3
3
|
/** @import { StandardSchemaV1 } from '@standard-schema/spec' */
|
|
4
4
|
import { get_request_store } from '@sveltejs/kit/internal/server';
|
|
5
5
|
import {
|
|
@@ -7,9 +7,10 @@ import {
|
|
|
7
7
|
set_nested_value,
|
|
8
8
|
deep_set,
|
|
9
9
|
normalize_issue,
|
|
10
|
-
flatten_issues
|
|
10
|
+
flatten_issues,
|
|
11
|
+
parse_form_key
|
|
11
12
|
} from '../../../form-utils.js';
|
|
12
|
-
import { get_cache, run_remote_function } from './shared.js';
|
|
13
|
+
import { get_cache, get_implicit_lookup, run_remote_function } from './shared.js';
|
|
13
14
|
import { ValidationError } from '@sveltejs/kit/internal';
|
|
14
15
|
|
|
15
16
|
/**
|
|
@@ -44,7 +45,7 @@ import { ValidationError } from '@sveltejs/kit/internal';
|
|
|
44
45
|
* @template {StandardSchemaV1<RemoteFormInput, Record<string, any>>} Schema
|
|
45
46
|
* @template Output
|
|
46
47
|
* @overload
|
|
47
|
-
* @param {Schema} validate
|
|
48
|
+
* @param {true extends HasNonOptionalBoolean<StandardSchemaV1.InferInput<Schema>> ? 'Error: All booleans in form schemas must be optional (e.g. `v.optional(v.boolean(), false)`) because checkbox inputs do not send a false value when unchecked.' : Schema} validate
|
|
48
49
|
* @param {(data: StandardSchemaV1.InferOutput<Schema>, issue: InvalidField<StandardSchemaV1.InferInput<Schema>>) => MaybePromise<Output>} fn
|
|
49
50
|
* @returns {RemoteForm<StandardSchemaV1.InferInput<Schema>, Output>}
|
|
50
51
|
* @since 2.27
|
|
@@ -71,8 +72,7 @@ export function form(validate_or_fn, maybe_fn) {
|
|
|
71
72
|
* @param {string | number | boolean} [key]
|
|
72
73
|
*/
|
|
73
74
|
function create_instance(key) {
|
|
74
|
-
/** @type {RemoteForm<Input, Output>} */
|
|
75
|
-
const instance = {};
|
|
75
|
+
const instance = /** @type {RemoteForm<Input, Output>} */ ({});
|
|
76
76
|
|
|
77
77
|
instance.method = 'POST';
|
|
78
78
|
|
|
@@ -88,8 +88,8 @@ export function form(validate_or_fn, maybe_fn) {
|
|
|
88
88
|
name: '',
|
|
89
89
|
id: '',
|
|
90
90
|
fn: async (data, meta, form_data) => {
|
|
91
|
-
|
|
92
|
-
|
|
91
|
+
const output =
|
|
92
|
+
/** @type {{ submission: true, input?: Record<string, any>, issues?: InternalRemoteFormIssue[], result: Output }} */ ({});
|
|
93
93
|
|
|
94
94
|
// make it possible to differentiate between user submission and programmatic `field.set(...)` updates
|
|
95
95
|
output.submission = true;
|
|
@@ -102,15 +102,12 @@ export function form(validate_or_fn, maybe_fn) {
|
|
|
102
102
|
}
|
|
103
103
|
|
|
104
104
|
if (validated?.issues !== undefined) {
|
|
105
|
-
handle_issues(output, validated.issues, form_data);
|
|
105
|
+
handle_issues(output, validated.issues, form_data, __.id);
|
|
106
106
|
} else {
|
|
107
107
|
if (validated !== undefined) {
|
|
108
108
|
data = validated.value;
|
|
109
109
|
}
|
|
110
110
|
|
|
111
|
-
state.remote.refreshes ??= new Map();
|
|
112
|
-
state.remote.reconnects ??= new Map();
|
|
113
|
-
|
|
114
111
|
const issue = create_issues();
|
|
115
112
|
|
|
116
113
|
try {
|
|
@@ -123,7 +120,7 @@ export function form(validate_or_fn, maybe_fn) {
|
|
|
123
120
|
);
|
|
124
121
|
} catch (e) {
|
|
125
122
|
if (e instanceof ValidationError) {
|
|
126
|
-
handle_issues(output, e.issues, form_data);
|
|
123
|
+
handle_issues(output, e.issues, form_data, __.id);
|
|
127
124
|
} else {
|
|
128
125
|
throw e;
|
|
129
126
|
}
|
|
@@ -133,7 +130,12 @@ export function form(validate_or_fn, maybe_fn) {
|
|
|
133
130
|
// We don't need to care about args or deduplicating calls, because uneval results are only relevant in full page reloads
|
|
134
131
|
// where only one form submission is active at the same time
|
|
135
132
|
if (!event.isRemoteRequest) {
|
|
136
|
-
get_cache(__, state)
|
|
133
|
+
const cache = get_cache(__, state);
|
|
134
|
+
cache[''] ??= output;
|
|
135
|
+
|
|
136
|
+
// register under the client-side action id so the output is serialized
|
|
137
|
+
// into the page, allowing the hydrated client to restore `result`/`issues`/`input`
|
|
138
|
+
get_implicit_lookup(__, state)[__.key ? `${__.id}/${__.key}` : __.id] = () => cache[''];
|
|
137
139
|
}
|
|
138
140
|
|
|
139
141
|
return output;
|
|
@@ -143,42 +145,55 @@ export function form(validate_or_fn, maybe_fn) {
|
|
|
143
145
|
Object.defineProperty(instance, '__', { value: __ });
|
|
144
146
|
|
|
145
147
|
Object.defineProperty(instance, 'action', {
|
|
146
|
-
get: () =>
|
|
148
|
+
get: () => {
|
|
149
|
+
const search = new URLSearchParams(get_request_store().event.url.search);
|
|
150
|
+
search.delete('/remote');
|
|
151
|
+
|
|
152
|
+
const query = search.toString();
|
|
153
|
+
const action_id = __.key ? `${__.id}/${encodeURIComponent(__.key)}` : __.id;
|
|
154
|
+
|
|
155
|
+
return `?${query ? `${query}&` : ''}/remote=${action_id}`;
|
|
156
|
+
},
|
|
147
157
|
enumerable: true
|
|
148
158
|
});
|
|
149
159
|
|
|
150
160
|
Object.defineProperty(instance, 'fields', {
|
|
151
161
|
get() {
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
162
|
+
// the form instance is created once per module and shared across requests,
|
|
163
|
+
// so the current request's state has to be resolved at access time
|
|
164
|
+
return create_field_proxy({
|
|
165
|
+
form_id: __.id,
|
|
166
|
+
get: () => get_cache(__, get_request_store().state)?.['']?.input ?? {},
|
|
167
|
+
set: (path, value) => {
|
|
168
|
+
const cache = get_cache(__, get_request_store().state);
|
|
157
169
|
const entry = cache[''];
|
|
158
170
|
|
|
159
|
-
if (entry?.
|
|
171
|
+
if (entry?.submission) {
|
|
160
172
|
// don't override a submission
|
|
161
173
|
return;
|
|
162
174
|
}
|
|
163
175
|
|
|
164
176
|
if (path.length === 0) {
|
|
165
|
-
(cache[''] ??= {
|
|
177
|
+
(cache[''] ??= {}).input = value;
|
|
166
178
|
return;
|
|
167
179
|
}
|
|
168
180
|
|
|
169
|
-
const input = entry?.
|
|
181
|
+
const input = entry?.input ?? {};
|
|
170
182
|
deep_set(input, path.map(String), value);
|
|
171
|
-
(cache[''] ??= {
|
|
183
|
+
(cache[''] ??= {}).input = input;
|
|
172
184
|
},
|
|
173
|
-
() =>
|
|
174
|
-
|
|
185
|
+
get_issues: () =>
|
|
186
|
+
flatten_issues(get_cache(__, get_request_store().state)?.['']?.issues ?? []),
|
|
187
|
+
get_touched: () => ({}),
|
|
188
|
+
get_dirty: () => ({})
|
|
189
|
+
});
|
|
175
190
|
}
|
|
176
191
|
});
|
|
177
192
|
|
|
178
193
|
Object.defineProperty(instance, 'result', {
|
|
179
194
|
get() {
|
|
180
195
|
try {
|
|
181
|
-
return get_cache(__)?.['']?.
|
|
196
|
+
return get_cache(__, get_request_store().state)?.['']?.result;
|
|
182
197
|
} catch {
|
|
183
198
|
return undefined;
|
|
184
199
|
}
|
|
@@ -190,6 +205,10 @@ export function form(validate_or_fn, maybe_fn) {
|
|
|
190
205
|
get: () => 0
|
|
191
206
|
});
|
|
192
207
|
|
|
208
|
+
Object.defineProperty(instance, 'submitted', {
|
|
209
|
+
get: () => false
|
|
210
|
+
});
|
|
211
|
+
|
|
193
212
|
Object.defineProperty(instance, 'preflight', {
|
|
194
213
|
// preflight is a noop on the server
|
|
195
214
|
value: () => instance
|
|
@@ -217,11 +236,15 @@ export function form(validate_or_fn, maybe_fn) {
|
|
|
217
236
|
value: (key) => {
|
|
218
237
|
const { state } = get_request_store();
|
|
219
238
|
const cache_key = __.id + '|' + JSON.stringify(key);
|
|
239
|
+
/** @type {RemoteForm<Input, Output> & { __: RemoteFormInternals }} */
|
|
220
240
|
let instance = (state.remote.forms ??= new Map()).get(cache_key);
|
|
221
241
|
|
|
222
242
|
if (!instance) {
|
|
223
|
-
instance =
|
|
224
|
-
|
|
243
|
+
instance = /** @type {RemoteForm<Input, Output> & { __: RemoteFormInternals }} */ (
|
|
244
|
+
create_instance(key)
|
|
245
|
+
);
|
|
246
|
+
instance.__.id = __.id;
|
|
247
|
+
instance.__.key = JSON.stringify(key);
|
|
225
248
|
instance.__.name = __.name;
|
|
226
249
|
|
|
227
250
|
state.remote.forms.set(cache_key, instance);
|
|
@@ -242,8 +265,9 @@ export function form(validate_or_fn, maybe_fn) {
|
|
|
242
265
|
* @param {{ issues?: InternalRemoteFormIssue[], input?: Record<string, any>, result: any }} output
|
|
243
266
|
* @param {readonly StandardSchemaV1.Issue[]} issues
|
|
244
267
|
* @param {FormData | null} form_data - null if the form is progressively enhanced
|
|
268
|
+
* @param {string} form_id - hash/name of the form
|
|
245
269
|
*/
|
|
246
|
-
function handle_issues(output, issues, form_data) {
|
|
270
|
+
function handle_issues(output, issues, form_data, form_id) {
|
|
247
271
|
output.issues = issues.map((issue) => normalize_issue(issue, true));
|
|
248
272
|
|
|
249
273
|
// if it was a progressively-enhanced submission, we don't need
|
|
@@ -251,19 +275,17 @@ function handle_issues(output, issues, form_data) {
|
|
|
251
275
|
if (form_data) {
|
|
252
276
|
output.input = {};
|
|
253
277
|
|
|
254
|
-
for (
|
|
278
|
+
for (const field_name of form_data.keys()) {
|
|
255
279
|
// redact sensitive fields
|
|
256
|
-
if (/^[.\]]?_/.test(
|
|
257
|
-
|
|
258
|
-
const is_array = key.endsWith('[]');
|
|
259
|
-
const values = form_data.getAll(key).filter((value) => typeof value === 'string');
|
|
280
|
+
if (/^[.\]]?_/.test(field_name)) continue;
|
|
260
281
|
|
|
261
|
-
|
|
282
|
+
const values = form_data.getAll(field_name).filter((value) => typeof value === 'string');
|
|
283
|
+
const field = parse_form_key(form_id, field_name);
|
|
262
284
|
|
|
263
285
|
set_nested_value(
|
|
264
286
|
/** @type {Record<string, any>} */ (output.input),
|
|
265
|
-
|
|
266
|
-
is_array ? values : values[0]
|
|
287
|
+
field,
|
|
288
|
+
field.is_array ? values : values[0]
|
|
267
289
|
);
|
|
268
290
|
}
|
|
269
291
|
}
|
|
@@ -1,19 +1,14 @@
|
|
|
1
|
-
/** @import { RemoteResource, RemotePrerenderFunction } from '@sveltejs/kit' */
|
|
2
|
-
/** @import { RemotePrerenderInputsGenerator, RemotePrerenderInternals, MaybePromise } from 'types' */
|
|
1
|
+
/** @import { RemoteResource, RemotePrerenderFunction } from '@sveltejs/kit/remote' */
|
|
2
|
+
/** @import { RemoteFunctionResponse, RemotePrerenderInputsGenerator, RemotePrerenderInternals, MaybePromise } from 'types' */
|
|
3
3
|
/** @import { StandardSchemaV1 } from '@standard-schema/spec' */
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
4
|
+
import { json } from '@sveltejs/kit';
|
|
5
|
+
import { HandledHttpError } from '@sveltejs/kit/internal';
|
|
6
6
|
import { get_request_store } from '@sveltejs/kit/internal/server';
|
|
7
|
-
import {
|
|
7
|
+
import { stringify_remote_arg } from '../../../shared.js';
|
|
8
|
+
import { parse, stringify } from '#app/internal/transport';
|
|
8
9
|
import { noop } from '../../../../utils/functions.js';
|
|
9
|
-
import { app_dir, base } from '
|
|
10
|
-
import {
|
|
11
|
-
create_validator,
|
|
12
|
-
get_cache,
|
|
13
|
-
get_response,
|
|
14
|
-
parse_remote_response,
|
|
15
|
-
run_remote_function
|
|
16
|
-
} from './shared.js';
|
|
10
|
+
import { app_dir, base } from '#app/paths';
|
|
11
|
+
import { create_validator, get_response, run_remote_function } from './shared.js';
|
|
17
12
|
|
|
18
13
|
/**
|
|
19
14
|
* Creates a remote prerender function. When called from the browser, the function will be invoked on the server via a `fetch` call.
|
|
@@ -89,50 +84,55 @@ export function prerender(validate_or_fn, fn_or_options, maybe_options) {
|
|
|
89
84
|
|
|
90
85
|
/** @type {RemotePrerenderFunction<Input, Output> & { __: RemotePrerenderInternals }} */
|
|
91
86
|
const wrapper = (arg) => {
|
|
87
|
+
const { event, state } = get_request_store();
|
|
88
|
+
const payload = stringify_remote_arg(arg);
|
|
89
|
+
|
|
90
|
+
// `get_response` (as opposed to bare `get_cache`) also registers the call in the
|
|
91
|
+
// implicit lookup, so that the result is inlined into the page payload (`data.p`)
|
|
92
|
+
// and the client doesn't need to fetch it again upon hydration
|
|
92
93
|
/** @type {Promise<Output> & Partial<RemoteResource<Output>>} */
|
|
93
|
-
const promise = (async () => {
|
|
94
|
-
const { event, state } = get_request_store();
|
|
95
|
-
const payload = stringify_remote_arg(arg, state.transport);
|
|
94
|
+
const promise = get_response(__, payload, state, async () => {
|
|
96
95
|
const id = __.id;
|
|
97
96
|
const url = `${base}/${app_dir}/remote/${id}${payload ? `/${payload}` : ''}`;
|
|
98
97
|
|
|
99
|
-
if (!state.prerendering && !
|
|
98
|
+
if (!state.prerendering && !__SVELTEKIT_DEV__ && !event.isRemoteRequest) {
|
|
99
|
+
/** @type {RemoteFunctionResponse | undefined} */
|
|
100
|
+
let prerendered;
|
|
101
|
+
|
|
100
102
|
try {
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
if (!response.ok) {
|
|
110
|
-
throw new Error('Prerendered response not found');
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
const prerendered = await response.json();
|
|
114
|
-
|
|
115
|
-
if (prerendered.type === 'error') {
|
|
116
|
-
error(prerendered.status, prerendered.error);
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
return prerendered.result;
|
|
120
|
-
})
|
|
121
|
-
}).data;
|
|
122
|
-
|
|
123
|
-
return parse_remote_response(await promise, state.transport);
|
|
124
|
-
});
|
|
103
|
+
// TODO adapters can provide prerendered data more efficiently than
|
|
104
|
+
// fetching from the public internet
|
|
105
|
+
// `request.url` rather than `event.url`, which throws inside queries
|
|
106
|
+
const response = await fetch(new URL(url, event.request.url).href);
|
|
107
|
+
|
|
108
|
+
if (response.ok) {
|
|
109
|
+
prerendered = /** @type {RemoteFunctionResponse} */ (await response.json());
|
|
110
|
+
}
|
|
125
111
|
} catch {
|
|
126
112
|
// not available prerendered, fallback to normal function
|
|
127
113
|
}
|
|
114
|
+
|
|
115
|
+
if (prerendered) {
|
|
116
|
+
if (prerendered.type === 'error') {
|
|
117
|
+
throw new HandledHttpError(prerendered.error);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
return parse(prerendered.data)._;
|
|
121
|
+
}
|
|
128
122
|
}
|
|
129
123
|
|
|
124
|
+
// during a prerender run, the same function might be invoked while rendering
|
|
125
|
+
// multiple pages — share the result across the entire run
|
|
130
126
|
if (state.prerendering?.remote_responses.has(url)) {
|
|
131
127
|
return /** @type {Promise<any>} */ (state.prerendering.remote_responses.get(url));
|
|
132
128
|
}
|
|
133
129
|
|
|
134
|
-
const promise =
|
|
135
|
-
|
|
130
|
+
const promise = run_remote_function(
|
|
131
|
+
event,
|
|
132
|
+
{ ...state, is_in_remote_prerender: true },
|
|
133
|
+
false,
|
|
134
|
+
() => validate(arg),
|
|
135
|
+
fn
|
|
136
136
|
);
|
|
137
137
|
|
|
138
138
|
if (state.prerendering) {
|
|
@@ -142,7 +142,7 @@ export function prerender(validate_or_fn, fn_or_options, maybe_options) {
|
|
|
142
142
|
const result = await promise;
|
|
143
143
|
|
|
144
144
|
if (state.prerendering) {
|
|
145
|
-
const body = { type: 'result',
|
|
145
|
+
const body = { type: 'result', data: stringify({ _: result }) };
|
|
146
146
|
state.prerendering.dependencies.set(url, {
|
|
147
147
|
body: JSON.stringify(body),
|
|
148
148
|
response: json(body)
|
|
@@ -151,7 +151,7 @@ export function prerender(validate_or_fn, fn_or_options, maybe_options) {
|
|
|
151
151
|
|
|
152
152
|
// TODO this is missing error/loading/current/status
|
|
153
153
|
return result;
|
|
154
|
-
})
|
|
154
|
+
});
|
|
155
155
|
|
|
156
156
|
promise.catch(noop);
|
|
157
157
|
|