@sveltejs/kit 3.0.0-next.11 → 3.0.0-next.12
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 +1 -1
- package/src/cli.js +8 -8
- package/src/constants.js +1 -1
- package/src/core/config/options.js +43 -35
- package/src/core/env.js +25 -11
- package/src/core/sync/sync.js +11 -14
- package/src/core/sync/utils.js +21 -1
- package/src/core/sync/{write_non_ambient.js → write_app_types.js} +23 -21
- package/src/core/sync/write_client_manifest.js +4 -12
- package/src/core/sync/write_env.js +6 -4
- package/src/core/sync/write_server.js +10 -15
- package/src/core/sync/write_tsconfig/index.js +245 -0
- package/src/core/sync/write_tsconfig/utils.js +162 -0
- package/src/core/sync/write_types/index.js +80 -88
- package/src/exports/internal/server/index.js +3 -1
- package/src/exports/public.d.ts +28 -51
- package/src/exports/vite/dev/index.js +88 -76
- package/src/exports/vite/index.js +364 -144
- package/src/exports/vite/module_ids.js +3 -1
- package/src/exports/vite/utils.js +1 -10
- package/src/runner.js +13 -0
- package/src/runtime/app/forms.js +4 -0
- package/src/runtime/app/manifest/index.js +1 -0
- package/src/runtime/app/paths/client.js +30 -30
- package/src/runtime/app/paths/internal/client.js +26 -0
- package/src/runtime/app/paths/server.js +22 -9
- package/src/runtime/app/paths/types.d.ts +11 -19
- package/src/runtime/app/server/remote/command.js +12 -7
- package/src/runtime/app/server/remote/form.js +29 -26
- package/src/runtime/app/server/remote/prerender.js +9 -2
- package/src/runtime/app/server/remote/query.js +5 -4
- package/src/runtime/app/server/remote/shared.js +48 -30
- package/src/runtime/app/service-worker/index.js +24 -0
- package/src/runtime/app/state/index.js +1 -1
- package/src/runtime/client/client.js +46 -9
- package/src/runtime/client/remote-functions/form.svelte.js +43 -51
- package/src/runtime/client/remote-functions/query/index.js +2 -2
- package/src/runtime/client/remote-functions/query-batch.svelte.js +2 -3
- package/src/runtime/client/remote-functions/query-live/iterator.js +5 -2
- package/src/runtime/client/remote-functions/shared.svelte.js +4 -1
- package/src/runtime/client/state.svelte.js +54 -21
- package/src/runtime/form-utils.js +89 -54
- package/src/runtime/server/cookie.js +1 -1
- package/src/runtime/server/data/index.js +31 -28
- package/src/runtime/server/errors.js +1 -1
- package/src/runtime/server/page/actions.js +3 -3
- package/src/runtime/server/page/render.js +19 -28
- package/src/runtime/server/remote-functions.js +66 -35
- package/src/runtime/server/respond.js +56 -14
- package/src/runtime/server/utils.js +10 -0
- package/src/types/ambient-private.d.ts +8 -0
- package/src/types/ambient.d.ts +22 -27
- package/src/types/global-private.d.ts +12 -0
- package/src/types/internal.d.ts +13 -3
- package/src/utils/url.js +12 -0
- package/src/version.js +1 -1
- package/types/index.d.ts +80 -98
- package/types/index.d.ts.map +4 -1
- package/src/core/sync/write_ambient.js +0 -18
- package/src/core/sync/write_tsconfig.js +0 -258
- /package/src/core/sync/{write_tsconfig_test → write_tsconfig/test-app}/package.json +0 -0
|
@@ -6,9 +6,11 @@ export const sveltekit_env_public_client = '\0virtual:__sveltekit/env/public/cli
|
|
|
6
6
|
export const sveltekit_env_public_server = '\0virtual:__sveltekit/env/public/server';
|
|
7
7
|
export const sveltekit_env_private = '\0virtual:__sveltekit/env/private';
|
|
8
8
|
export const sveltekit_env_service_worker = '\0virtual:__sveltekit/env/service-worker';
|
|
9
|
-
|
|
9
|
+
export const sveltekit_server = '\0virtual:__sveltekit/server';
|
|
10
10
|
export const service_worker = '\0virtual:service-worker';
|
|
11
11
|
|
|
12
|
+
export const sveltekit_manifest_data = '\0virtual:__sveltekit/manifest-data';
|
|
13
|
+
|
|
12
14
|
export const app_server = posixify(
|
|
13
15
|
fileURLToPath(new URL('../../runtime/app/server/index.js', import.meta.url))
|
|
14
16
|
);
|
|
@@ -4,12 +4,7 @@ import { negotiate } from '../../utils/http.js';
|
|
|
4
4
|
import { escape_html } from '../../utils/escape.js';
|
|
5
5
|
import { stackless } from '../../utils/error.js';
|
|
6
6
|
import { dedent } from '../../core/sync/utils.js';
|
|
7
|
-
import {
|
|
8
|
-
app_server,
|
|
9
|
-
app_env_private,
|
|
10
|
-
service_worker,
|
|
11
|
-
sveltekit_env_private
|
|
12
|
-
} from './module_ids.js';
|
|
7
|
+
import { app_server, app_env_private, sveltekit_env_private } from './module_ids.js';
|
|
13
8
|
import { styleText } from 'node:util';
|
|
14
9
|
|
|
15
10
|
/**
|
|
@@ -143,10 +138,6 @@ export function normalize_id(id, aliases, cwd) {
|
|
|
143
138
|
return '$app/env/private';
|
|
144
139
|
}
|
|
145
140
|
|
|
146
|
-
if (id === service_worker) {
|
|
147
|
-
return '$service-worker';
|
|
148
|
-
}
|
|
149
|
-
|
|
150
141
|
return posixify(id);
|
|
151
142
|
}
|
|
152
143
|
|
package/src/runner.js
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/** @import { ViteDevServer } from 'vite' */
|
|
2
|
+
import * as vite from 'vite';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* @param {ViteDevServer} server
|
|
6
|
+
*/
|
|
7
|
+
export function get_runner(server) {
|
|
8
|
+
if (!vite.isRunnableDevEnvironment(server.environments.ssr)) {
|
|
9
|
+
throw new Error('The configured Vite SSR environment must be a RunnableDevEnvironment');
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
return server.environments.ssr.runner;
|
|
13
|
+
}
|
package/src/runtime/app/forms.js
CHANGED
|
@@ -4,6 +4,7 @@ import { noop } from '../../utils/functions.js';
|
|
|
4
4
|
import { refreshAll } from './navigation.js';
|
|
5
5
|
import { app as client_app, applyAction, handle_error } from '../client/client.js';
|
|
6
6
|
import { app as server_app } from '../server/app.js';
|
|
7
|
+
import { notify_version } from '../client/state.svelte.js';
|
|
7
8
|
|
|
8
9
|
export { applyAction };
|
|
9
10
|
|
|
@@ -201,6 +202,9 @@ export function enhance(form_element, submit = noop) {
|
|
|
201
202
|
signal: controller.signal
|
|
202
203
|
});
|
|
203
204
|
|
|
205
|
+
// detect new deployments from the response header
|
|
206
|
+
notify_version(response.headers.get('x-sveltekit-version'));
|
|
207
|
+
|
|
204
208
|
if (response.status === 204) {
|
|
205
209
|
result = { type: 'success', status: 204 };
|
|
206
210
|
} else {
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from '__sveltekit/manifest-data';
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
/** @import {
|
|
1
|
+
/** @import { AssetPath, RouteId, RouteIdWithSearchOrHash, Path, PathnameWithSearchOrHash, ResolvedPathname, RouteParams } from '$app/types' */
|
|
2
2
|
/** @import { ResolveArgs } from './types.js' */
|
|
3
|
-
import { base, assets, hash_routing } from './internal/client.js';
|
|
3
|
+
import { base, assets, hash_routing, match_implementation } from './internal/client.js';
|
|
4
4
|
import { resolve_route } from '../../../utils/routing.js';
|
|
5
|
-
import {
|
|
5
|
+
import { DEV } from 'esm-env';
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
8
|
* Resolve the URL of an asset in your `static` directory, by prefixing it with [`config.paths.assets`](https://svelte.dev/docs/kit/configuration#paths) if configured, or otherwise by prefixing it with the base path.
|
|
@@ -15,15 +15,24 @@ import { get_navigation_intent } from '../../client/client.js';
|
|
|
15
15
|
* import { asset } from '$app/paths';
|
|
16
16
|
* </script>
|
|
17
17
|
*
|
|
18
|
-
* <img alt="a potato" src={asset('
|
|
18
|
+
* <img alt="a potato" src={asset('potato.jpg')} />
|
|
19
19
|
* ```
|
|
20
20
|
* @since 2.26
|
|
21
21
|
*
|
|
22
|
-
* @param {
|
|
22
|
+
* @param {AssetPath} file
|
|
23
23
|
* @returns {string}
|
|
24
24
|
*/
|
|
25
25
|
export function asset(file) {
|
|
26
|
-
|
|
26
|
+
// TODO 4.0 remove this
|
|
27
|
+
if (file[0] === '/') {
|
|
28
|
+
if (DEV) {
|
|
29
|
+
console.warn(`\`asset('${file}')\` should now be \`asset('${file.slice(1)}')\``);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
file = file.slice(1);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
return (assets || base) + '/' + file;
|
|
27
36
|
}
|
|
28
37
|
|
|
29
38
|
const pathname_prefix = hash_routing ? '#' : '';
|
|
@@ -38,7 +47,7 @@ const pathname_prefix = hash_routing ? '#' : '';
|
|
|
38
47
|
* import { resolve } from '$app/paths';
|
|
39
48
|
*
|
|
40
49
|
* // using a pathname
|
|
41
|
-
* const resolved = resolve(
|
|
50
|
+
* const resolved = resolve(`blog/hello-world`);
|
|
42
51
|
*
|
|
43
52
|
* // using a route ID plus parameters
|
|
44
53
|
* const resolved = resolve('/blog/[slug]', {
|
|
@@ -52,14 +61,18 @@ const pathname_prefix = hash_routing ? '#' : '';
|
|
|
52
61
|
* @returns {ResolvedPathname}
|
|
53
62
|
*/
|
|
54
63
|
export function resolve(...args) {
|
|
55
|
-
if (
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
)
|
|
64
|
+
if (args[0][0] === '/') {
|
|
65
|
+
const [id, params] = args;
|
|
66
|
+
|
|
67
|
+
// route ID
|
|
68
|
+
if (id.includes('[') && !params) {
|
|
69
|
+
throw new Error(`Missing params for dynamic route ID ${id}`);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
return base + pathname_prefix + resolve_route(args[0], args[1] ?? {});
|
|
60
73
|
}
|
|
61
74
|
|
|
62
|
-
return base + pathname_prefix +
|
|
75
|
+
return base + pathname_prefix + '/' + args[0];
|
|
63
76
|
}
|
|
64
77
|
|
|
65
78
|
/**
|
|
@@ -69,7 +82,7 @@ export function resolve(...args) {
|
|
|
69
82
|
* ```js
|
|
70
83
|
* import { match } from '$app/paths';
|
|
71
84
|
*
|
|
72
|
-
* const route = await match('
|
|
85
|
+
* const route = await match('blog/hello-world');
|
|
73
86
|
*
|
|
74
87
|
* if (route?.id === '/blog/[slug]') {
|
|
75
88
|
* const slug = route.params.slug;
|
|
@@ -79,22 +92,9 @@ export function resolve(...args) {
|
|
|
79
92
|
* ```
|
|
80
93
|
* @since 2.52.0
|
|
81
94
|
*
|
|
82
|
-
* @param {
|
|
95
|
+
* @param {Path | URL | (string & {})} url
|
|
83
96
|
* @returns {Promise<{ [K in RouteId]: { id: K; params: RouteParams<K>; } }[RouteId] | null>}
|
|
84
97
|
*/
|
|
85
|
-
export
|
|
86
|
-
|
|
87
|
-
url = new URL(url, location.href);
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
const intent = await get_navigation_intent(url, false);
|
|
91
|
-
|
|
92
|
-
if (intent) {
|
|
93
|
-
return {
|
|
94
|
-
id: /** @type {RouteId} */ (intent.route.id),
|
|
95
|
-
params: intent.params
|
|
96
|
-
};
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
return null;
|
|
98
|
+
export function match(url) {
|
|
99
|
+
return match_implementation(url);
|
|
100
100
|
}
|
|
@@ -1,6 +1,32 @@
|
|
|
1
|
+
/** @import { RouteId, Path } from '$app/types' */
|
|
1
2
|
import { payload } from '../../../client/payload.js';
|
|
2
3
|
|
|
3
4
|
export const base = payload.base ?? __SVELTEKIT_PATHS_BASE__;
|
|
4
5
|
export const assets = payload.assets ?? base ?? __SVELTEKIT_PATHS_ASSETS__;
|
|
5
6
|
export const app_dir = __SVELTEKIT_APP_DIR__;
|
|
6
7
|
export const hash_routing = __SVELTEKIT_HASH_ROUTING__;
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* We make this configurable per-environment so that it's possible to import `$app/paths`
|
|
11
|
+
* into a service worker without importing the entire client
|
|
12
|
+
* @param {Path | URL | (string & {})} _url
|
|
13
|
+
* @returns {Promise<{ [K in RouteId]: { id: K; params: import('$app/types').RouteParams<K>; } }[RouteId] | null>}
|
|
14
|
+
*/
|
|
15
|
+
// eslint-disable-next-line @typescript-eslint/require-await
|
|
16
|
+
export let match_implementation = async (_url) => {
|
|
17
|
+
// @ts-ignore
|
|
18
|
+
if (typeof ServiceWorkerGlobalScope !== 'undefined' && self instanceof ServiceWorkerGlobalScope) {
|
|
19
|
+
throw new Error(
|
|
20
|
+
'Cannot use `match(...)` inside a service worker, as it depends on the SvelteKit client instance'
|
|
21
|
+
);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
return null;
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* @param {typeof match_implementation} fn
|
|
29
|
+
*/
|
|
30
|
+
export function set_match_implementation(fn) {
|
|
31
|
+
match_implementation = fn;
|
|
32
|
+
}
|
|
@@ -5,23 +5,36 @@ import { add_data_suffix } from '../../pathname.js';
|
|
|
5
5
|
import { try_get_request_store } from '@sveltejs/kit/internal/server';
|
|
6
6
|
import { manifest } from '../../server/internal.js';
|
|
7
7
|
import { get_hooks } from '__SERVER__/internal.js';
|
|
8
|
+
import { DEV } from 'esm-env';
|
|
8
9
|
|
|
9
10
|
/** @type {import('./client.js').asset} */
|
|
10
11
|
export function asset(file) {
|
|
11
|
-
//
|
|
12
|
-
|
|
12
|
+
// TODO 4.0 remove this
|
|
13
|
+
if (file[0] === '/') {
|
|
14
|
+
if (DEV) {
|
|
15
|
+
console.warn(`\`asset('${file}')\` should now be \`asset('${file.slice(1)}')\``);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
file = file.slice(1);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
return assets !== base ? `${assets}/${file}` : resolve(file);
|
|
13
22
|
}
|
|
14
23
|
|
|
15
24
|
/** @type {import('./client.js').resolve} */
|
|
16
25
|
export function resolve(id, params) {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
)
|
|
22
|
-
|
|
26
|
+
let resolved;
|
|
27
|
+
|
|
28
|
+
if (id[0] === '/') {
|
|
29
|
+
// route ID
|
|
30
|
+
if (id.includes('[') && !params) {
|
|
31
|
+
throw new Error(`Missing params for dynamic route ID ${id}`);
|
|
32
|
+
}
|
|
23
33
|
|
|
24
|
-
|
|
34
|
+
resolved = resolve_route(id, params ?? {});
|
|
35
|
+
} else {
|
|
36
|
+
resolved = '/' + id;
|
|
37
|
+
}
|
|
25
38
|
|
|
26
39
|
if (relative) {
|
|
27
40
|
const store = try_get_request_store();
|
|
@@ -1,23 +1,15 @@
|
|
|
1
|
-
import {
|
|
2
|
-
PathnameWithSearchOrHash,
|
|
3
|
-
RouteId,
|
|
4
|
-
RouteIdWithSearchOrHash,
|
|
5
|
-
RouteParams
|
|
6
|
-
} from '$app/types';
|
|
1
|
+
import { RouteId, RouteParams } from '$app/types';
|
|
7
2
|
|
|
8
|
-
type StripSearchOrHash<T extends string> = T extends `${infer
|
|
9
|
-
?
|
|
10
|
-
: T extends `${infer
|
|
11
|
-
?
|
|
3
|
+
type StripSearchOrHash<T extends string> = T extends `${infer U}?${string}`
|
|
4
|
+
? U
|
|
5
|
+
: T extends `${infer U}#${string}`
|
|
6
|
+
? U
|
|
12
7
|
: T;
|
|
13
8
|
|
|
14
|
-
export type ResolveArgs<T
|
|
15
|
-
T extends RouteId
|
|
16
|
-
? RouteParams<
|
|
9
|
+
export type ResolveArgs<T> = T extends `/${string}`
|
|
10
|
+
? StripSearchOrHash<T> extends infer U extends RouteId
|
|
11
|
+
? RouteParams<U> extends Record<string, never>
|
|
17
12
|
? [route: T]
|
|
18
|
-
: [route: T, params: RouteParams<
|
|
19
|
-
:
|
|
20
|
-
|
|
21
|
-
? [route: T]
|
|
22
|
-
: [route: T, params: RouteParams<U>]
|
|
23
|
-
: [route: T];
|
|
13
|
+
: [route: T, params: RouteParams<U>]
|
|
14
|
+
: [never]
|
|
15
|
+
: [pathname: T];
|
|
@@ -65,16 +65,21 @@ 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
85
|
const promise = Promise.resolve(
|
|
@@ -7,7 +7,8 @@ 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
13
|
import { get_cache, get_implicit_lookup, run_remote_function } from './shared.js';
|
|
13
14
|
import { ValidationError } from '@sveltejs/kit/internal';
|
|
@@ -102,7 +103,7 @@ export function form(validate_or_fn, maybe_fn) {
|
|
|
102
103
|
}
|
|
103
104
|
|
|
104
105
|
if (validated?.issues !== undefined) {
|
|
105
|
-
handle_issues(output, validated.issues, form_data);
|
|
106
|
+
handle_issues(output, validated.issues, form_data, __.id);
|
|
106
107
|
} else {
|
|
107
108
|
if (validated !== undefined) {
|
|
108
109
|
data = validated.value;
|
|
@@ -120,7 +121,7 @@ export function form(validate_or_fn, maybe_fn) {
|
|
|
120
121
|
);
|
|
121
122
|
} catch (e) {
|
|
122
123
|
if (e instanceof ValidationError) {
|
|
123
|
-
handle_issues(output, e.issues, form_data);
|
|
124
|
+
handle_issues(output, e.issues, form_data, __.id);
|
|
124
125
|
} else {
|
|
125
126
|
throw e;
|
|
126
127
|
}
|
|
@@ -135,7 +136,7 @@ export function form(validate_or_fn, maybe_fn) {
|
|
|
135
136
|
|
|
136
137
|
// register under the client-side action id so the output is serialized
|
|
137
138
|
// into the page, allowing the hydrated client to restore `result`/`issues`/`input`
|
|
138
|
-
get_implicit_lookup(__, state)[__.
|
|
139
|
+
get_implicit_lookup(__, state)[__.key ? `${__.id}/${__.key}` : __.id] = () => cache[''];
|
|
139
140
|
}
|
|
140
141
|
|
|
141
142
|
return output;
|
|
@@ -145,7 +146,7 @@ export function form(validate_or_fn, maybe_fn) {
|
|
|
145
146
|
Object.defineProperty(instance, '__', { value: __ });
|
|
146
147
|
|
|
147
148
|
Object.defineProperty(instance, 'action', {
|
|
148
|
-
get: () => `?/remote=${__.id}`,
|
|
149
|
+
get: () => `?/remote=${__.key ? `${__.id}/${encodeURIComponent(__.key)}` : __.id}`,
|
|
149
150
|
enumerable: true
|
|
150
151
|
});
|
|
151
152
|
|
|
@@ -153,10 +154,10 @@ export function form(validate_or_fn, maybe_fn) {
|
|
|
153
154
|
get() {
|
|
154
155
|
// the form instance is created once per module and shared across requests,
|
|
155
156
|
// so the current request's state has to be resolved at access time
|
|
156
|
-
return create_field_proxy(
|
|
157
|
-
|
|
158
|
-
() => get_cache(__, get_request_store().state)?.['']?.input ?? {},
|
|
159
|
-
(path, value) => {
|
|
157
|
+
return create_field_proxy({
|
|
158
|
+
form_id: __.id,
|
|
159
|
+
get: () => get_cache(__, get_request_store().state)?.['']?.input ?? {},
|
|
160
|
+
set: (path, value) => {
|
|
160
161
|
const cache = get_cache(__, get_request_store().state);
|
|
161
162
|
const entry = cache[''];
|
|
162
163
|
|
|
@@ -174,11 +175,11 @@ export function form(validate_or_fn, maybe_fn) {
|
|
|
174
175
|
deep_set(input, path.map(String), value);
|
|
175
176
|
(cache[''] ??= {}).input = input;
|
|
176
177
|
},
|
|
177
|
-
() =>
|
|
178
|
-
|
|
179
|
-
() => ({}),
|
|
180
|
-
|
|
181
|
-
);
|
|
178
|
+
get_issues: () =>
|
|
179
|
+
flatten_issues(get_cache(__, get_request_store().state)?.['']?.issues ?? []),
|
|
180
|
+
get_touched: () => ({}),
|
|
181
|
+
get_dirty: () => ({})
|
|
182
|
+
});
|
|
182
183
|
}
|
|
183
184
|
});
|
|
184
185
|
|
|
@@ -228,12 +229,15 @@ export function form(validate_or_fn, maybe_fn) {
|
|
|
228
229
|
value: (key) => {
|
|
229
230
|
const { state } = get_request_store();
|
|
230
231
|
const cache_key = __.id + '|' + JSON.stringify(key);
|
|
232
|
+
/** @type {RemoteForm<Input, Output> & { __: RemoteFormInternals }} */
|
|
231
233
|
let instance = (state.remote.forms ??= new Map()).get(cache_key);
|
|
232
234
|
|
|
233
235
|
if (!instance) {
|
|
234
|
-
instance =
|
|
235
|
-
|
|
236
|
-
|
|
236
|
+
instance = /** @type {RemoteForm<Input, Output> & { __: RemoteFormInternals }} */ (
|
|
237
|
+
create_instance(key)
|
|
238
|
+
);
|
|
239
|
+
instance.__.id = __.id;
|
|
240
|
+
instance.__.key = JSON.stringify(key);
|
|
237
241
|
instance.__.name = __.name;
|
|
238
242
|
|
|
239
243
|
state.remote.forms.set(cache_key, instance);
|
|
@@ -254,8 +258,9 @@ export function form(validate_or_fn, maybe_fn) {
|
|
|
254
258
|
* @param {{ issues?: InternalRemoteFormIssue[], input?: Record<string, any>, result: any }} output
|
|
255
259
|
* @param {readonly StandardSchemaV1.Issue[]} issues
|
|
256
260
|
* @param {FormData | null} form_data - null if the form is progressively enhanced
|
|
261
|
+
* @param {string} form_id - hash/name of the form
|
|
257
262
|
*/
|
|
258
|
-
function handle_issues(output, issues, form_data) {
|
|
263
|
+
function handle_issues(output, issues, form_data, form_id) {
|
|
259
264
|
output.issues = issues.map((issue) => normalize_issue(issue, true));
|
|
260
265
|
|
|
261
266
|
// if it was a progressively-enhanced submission, we don't need
|
|
@@ -263,19 +268,17 @@ function handle_issues(output, issues, form_data) {
|
|
|
263
268
|
if (form_data) {
|
|
264
269
|
output.input = {};
|
|
265
270
|
|
|
266
|
-
for (
|
|
271
|
+
for (const field_name of form_data.keys()) {
|
|
267
272
|
// redact sensitive fields
|
|
268
|
-
if (/^[.\]]?_/.test(
|
|
269
|
-
|
|
270
|
-
const is_array = key.endsWith('[]');
|
|
271
|
-
const values = form_data.getAll(key).filter((value) => typeof value === 'string');
|
|
273
|
+
if (/^[.\]]?_/.test(field_name)) continue;
|
|
272
274
|
|
|
273
|
-
|
|
275
|
+
const values = form_data.getAll(field_name).filter((value) => typeof value === 'string');
|
|
276
|
+
const field = parse_form_key(form_id, field_name);
|
|
274
277
|
|
|
275
278
|
set_nested_value(
|
|
276
279
|
/** @type {Record<string, any>} */ (output.input),
|
|
277
|
-
|
|
278
|
-
is_array ? values : values[0]
|
|
280
|
+
field,
|
|
281
|
+
field.is_array ? values : values[0]
|
|
279
282
|
);
|
|
280
283
|
}
|
|
281
284
|
}
|
|
@@ -102,7 +102,8 @@ export function prerender(validate_or_fn, fn_or_options, maybe_options) {
|
|
|
102
102
|
try {
|
|
103
103
|
// TODO adapters can provide prerendered data more efficiently than
|
|
104
104
|
// fetching from the public internet
|
|
105
|
-
|
|
105
|
+
// `request.url` rather than `event.url`, which throws inside queries
|
|
106
|
+
const response = await fetch(new URL(url, event.request.url).href);
|
|
106
107
|
|
|
107
108
|
if (!response.ok) {
|
|
108
109
|
throw new Error('Prerendered response not found');
|
|
@@ -126,7 +127,13 @@ export function prerender(validate_or_fn, fn_or_options, maybe_options) {
|
|
|
126
127
|
return /** @type {Promise<any>} */ (state.prerendering.remote_responses.get(url));
|
|
127
128
|
}
|
|
128
129
|
|
|
129
|
-
const promise = run_remote_function(
|
|
130
|
+
const promise = run_remote_function(
|
|
131
|
+
event,
|
|
132
|
+
{ ...state, is_in_remote_prerender: true },
|
|
133
|
+
false,
|
|
134
|
+
() => validate(arg),
|
|
135
|
+
fn
|
|
136
|
+
);
|
|
130
137
|
|
|
131
138
|
if (state.prerendering) {
|
|
132
139
|
state.prerendering.remote_responses.set(url, promise);
|
|
@@ -404,17 +404,18 @@ export function refresh(event, state, internals, payload, fn) {
|
|
|
404
404
|
return;
|
|
405
405
|
}
|
|
406
406
|
|
|
407
|
-
if (!event.isRemoteRequest) {
|
|
408
|
-
// or this is a no-JS form submission
|
|
407
|
+
if (!event.isRemoteRequest && state.is_in_remote_form_or_command) {
|
|
408
|
+
// ...or this is a no-JS (native) form submission, where the page re-renders
|
|
409
|
+
// anyway so there's no live client cache to apply a single-flight update to.
|
|
409
410
|
return;
|
|
410
411
|
}
|
|
411
412
|
|
|
412
413
|
const key = create_remote_key(internals.id, payload);
|
|
413
414
|
|
|
414
415
|
// `fn` is stored rather than invoked eagerly. The query is run at the end of
|
|
415
|
-
// the
|
|
416
|
+
// the request (in `collect_remote_data`), so that it observes any state
|
|
416
417
|
// mutations that happen after `refresh()` is called. If the developer re-awaits
|
|
417
|
-
// the query before the
|
|
418
|
+
// the query before the request finishes, the cache entry created by that await
|
|
418
419
|
// is reused instead of re-running the query.
|
|
419
420
|
(state.remote.explicit ??= new Map()).set(key, {
|
|
420
421
|
internals,
|
|
@@ -37,7 +37,7 @@ export function create_validator(validate_or_fn, maybe_fn) {
|
|
|
37
37
|
if (result.issues) {
|
|
38
38
|
const body = await state.handleValidationError({
|
|
39
39
|
issues: result.issues,
|
|
40
|
-
event
|
|
40
|
+
event: state.original_event ?? event
|
|
41
41
|
});
|
|
42
42
|
error(body.status ?? 400, body);
|
|
43
43
|
}
|
|
@@ -101,40 +101,58 @@ export function parse_remote_response(data, transport) {
|
|
|
101
101
|
* @returns {RequestStore}
|
|
102
102
|
*/
|
|
103
103
|
function derive_remote_function_event(event, state, allow_cookies) {
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
104
|
+
/** @type {RequestEvent} */
|
|
105
|
+
const derived = {
|
|
106
|
+
...event,
|
|
107
|
+
setHeaders: () => {
|
|
108
|
+
throw new Error('setHeaders is not allowed in remote functions');
|
|
109
|
+
},
|
|
110
|
+
cookies: {
|
|
111
|
+
...event.cookies,
|
|
112
|
+
set: (name, value, opts) => {
|
|
113
|
+
if (!allow_cookies) {
|
|
114
|
+
throw new Error('Cannot set cookies in `query` or `prerender` functions');
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
if (opts.path && !opts.path.startsWith('/')) {
|
|
118
|
+
throw new Error('Cookies set in remote functions must have an absolute path');
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
return event.cookies.set(name, value, opts);
|
|
109
122
|
},
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
if (opts.path && !opts.path.startsWith('/')) {
|
|
118
|
-
throw new Error('Cookies set in remote functions must have an absolute path');
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
return event.cookies.set(name, value, opts);
|
|
122
|
-
},
|
|
123
|
-
delete: (name, opts) => {
|
|
124
|
-
if (!allow_cookies) {
|
|
125
|
-
throw new Error('Cannot delete cookies in `query` or `prerender` functions');
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
if (opts.path && !opts.path.startsWith('/')) {
|
|
129
|
-
throw new Error('Cookies deleted in remote functions must have an absolute path');
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
return event.cookies.delete(name, opts);
|
|
123
|
+
delete: (name, opts) => {
|
|
124
|
+
if (!allow_cookies) {
|
|
125
|
+
throw new Error('Cannot delete cookies in `query` or `prerender` functions');
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
if (opts.path && !opts.path.startsWith('/')) {
|
|
129
|
+
throw new Error('Cookies deleted in remote functions must have an absolute path');
|
|
133
130
|
}
|
|
131
|
+
|
|
132
|
+
return event.cookies.delete(name, opts);
|
|
134
133
|
}
|
|
135
|
-
}
|
|
134
|
+
}
|
|
135
|
+
};
|
|
136
|
+
|
|
137
|
+
if (state.is_in_remote_query) {
|
|
138
|
+
for (const property of ['url', 'params', 'route']) {
|
|
139
|
+
// non-enumerable so spreading for a nested derivation doesn't invoke the getter
|
|
140
|
+
Object.defineProperty(derived, property, {
|
|
141
|
+
enumerable: false,
|
|
142
|
+
get() {
|
|
143
|
+
throw new Error(
|
|
144
|
+
`Cannot access event.${property} in a query. Pass the value as an argument to the query instead`
|
|
145
|
+
);
|
|
146
|
+
}
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
return {
|
|
152
|
+
event: derived,
|
|
136
153
|
state: {
|
|
137
154
|
...state,
|
|
155
|
+
original_event: state.original_event ?? event,
|
|
138
156
|
is_in_remote_function: true
|
|
139
157
|
}
|
|
140
158
|
};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/// <reference no-default-lib="true"/>
|
|
2
|
+
/// <reference lib="esnext" />
|
|
3
|
+
/// <reference lib="webworker" />
|
|
4
|
+
|
|
5
|
+
import { DEV } from 'esm-env';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* The execution context of a service worker. This export exists to make it easier to
|
|
9
|
+
* use service workers with the correct types, provided the importing module is governed
|
|
10
|
+
* by a `tsconfig.json` that extends [`$app/tsconfig/service-worker`](https://svelte.dev/docs/kit/$app-tsconfig-service-worker).
|
|
11
|
+
*
|
|
12
|
+
*/
|
|
13
|
+
export const self = /** @type {ServiceWorkerGlobalScope} */ (
|
|
14
|
+
/** @type {unknown} */ (globalThis.self)
|
|
15
|
+
);
|
|
16
|
+
|
|
17
|
+
if (DEV) {
|
|
18
|
+
if (
|
|
19
|
+
typeof ServiceWorkerGlobalScope === 'undefined' ||
|
|
20
|
+
!(self instanceof ServiceWorkerGlobalScope)
|
|
21
|
+
) {
|
|
22
|
+
throw new Error('The `$app/service-worker` module can only be imported into a service worker');
|
|
23
|
+
}
|
|
24
|
+
}
|
|
@@ -58,7 +58,7 @@ export const page = BROWSER ? client_page : server_page;
|
|
|
58
58
|
export const navigating = BROWSER ? client_navigating : server_navigating;
|
|
59
59
|
|
|
60
60
|
/**
|
|
61
|
-
* A read-only reactive value that's initially `false`.
|
|
61
|
+
* A read-only reactive value that's initially `false`. SvelteKit checks for new versions on data, remote, and form action responses (via the `x-sveltekit-version` header), when the tab regains focus or becomes visible, and on a poll interval (see [`version.pollInterval`](https://svelte.dev/docs/kit/configuration#version)). `updated.current` is set to `true` when a new version is detected. `updated.check()` will force an immediate check, regardless of polling.
|
|
62
62
|
* @type {{ get current(): boolean; check(): Promise<boolean>; }}
|
|
63
63
|
*/
|
|
64
64
|
export const updated = BROWSER ? client_updated : server_updated;
|