@sveltejs/kit 2.26.1 → 2.27.1
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/README.md +1 -1
- package/package.json +3 -2
- package/src/core/adapt/builder.js +6 -1
- package/src/core/config/options.js +4 -0
- package/src/core/generate_manifest/index.js +4 -1
- package/src/core/postbuild/analyse.js +25 -1
- package/src/core/postbuild/fallback.js +2 -1
- package/src/core/postbuild/prerender.js +41 -10
- package/src/core/sync/create_manifest_data/index.js +35 -1
- package/src/core/sync/write_server.js +4 -2
- package/src/exports/index.js +1 -1
- package/src/exports/internal/index.js +3 -1
- package/src/exports/internal/remote-functions.js +21 -0
- package/src/exports/public.d.ts +162 -2
- package/src/exports/vite/build/build_remote.js +129 -0
- package/src/exports/vite/dev/index.js +7 -0
- package/src/exports/vite/index.js +123 -8
- package/src/exports/vite/preview/index.js +3 -1
- package/src/runtime/app/navigation.js +1 -0
- package/src/runtime/app/server/index.js +2 -0
- package/src/runtime/app/server/remote/command.js +91 -0
- package/src/runtime/app/server/remote/form.js +124 -0
- package/src/runtime/app/server/remote/index.js +4 -0
- package/src/runtime/app/server/remote/prerender.js +163 -0
- package/src/runtime/app/server/remote/query.js +115 -0
- package/src/runtime/app/server/remote/shared.js +153 -0
- package/src/runtime/client/client.js +107 -39
- package/src/runtime/client/fetcher.js +1 -1
- package/src/runtime/client/remote-functions/command.js +71 -0
- package/src/runtime/client/remote-functions/form.svelte.js +312 -0
- package/src/runtime/client/remote-functions/index.js +4 -0
- package/src/runtime/client/remote-functions/prerender.svelte.js +166 -0
- package/src/runtime/client/remote-functions/query.svelte.js +219 -0
- package/src/runtime/client/remote-functions/shared.svelte.js +143 -0
- package/src/runtime/client/types.d.ts +2 -0
- package/src/runtime/server/data/index.js +6 -4
- package/src/runtime/server/event-state.js +41 -0
- package/src/runtime/server/index.js +12 -3
- package/src/runtime/server/page/actions.js +1 -1
- package/src/runtime/server/page/index.js +10 -3
- package/src/runtime/server/page/load_data.js +18 -12
- package/src/runtime/server/page/render.js +33 -7
- package/src/runtime/server/page/serialize_data.js +1 -1
- package/src/runtime/server/remote.js +237 -0
- package/src/runtime/server/respond.js +57 -36
- package/src/runtime/shared.js +61 -0
- package/src/types/global-private.d.ts +2 -0
- package/src/types/internal.d.ts +52 -5
- package/src/types/synthetic/$env+static+private.md +1 -1
- package/src/utils/routing.js +2 -2
- package/src/version.js +1 -1
- package/types/index.d.ts +271 -8
- package/types/index.d.ts.map +14 -1
- /package/src/{runtime → utils}/hash.js +0 -0
package/README.md
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sveltejs/kit",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.27.1",
|
|
4
4
|
"description": "SvelteKit is the fastest way to build Svelte apps",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"framework",
|
|
@@ -18,6 +18,7 @@
|
|
|
18
18
|
"homepage": "https://svelte.dev",
|
|
19
19
|
"type": "module",
|
|
20
20
|
"dependencies": {
|
|
21
|
+
"@standard-schema/spec": "^1.0.0",
|
|
21
22
|
"@sveltejs/acorn-typescript": "^1.0.5",
|
|
22
23
|
"@types/cookie": "^0.6.0",
|
|
23
24
|
"acorn": "^8.14.1",
|
|
@@ -37,7 +38,7 @@
|
|
|
37
38
|
"@types/connect": "^3.4.38",
|
|
38
39
|
"@types/node": "^18.19.119",
|
|
39
40
|
"@types/set-cookie-parser": "^2.4.7",
|
|
40
|
-
"dts-buddy": "^0.6.
|
|
41
|
+
"dts-buddy": "^0.6.2",
|
|
41
42
|
"rollup": "^4.14.2",
|
|
42
43
|
"svelte": "^5.35.5",
|
|
43
44
|
"svelte-preprocess": "^6.0.0",
|
|
@@ -219,7 +219,12 @@ export function create_builder({
|
|
|
219
219
|
|
|
220
220
|
writePrerendered(dest) {
|
|
221
221
|
const source = `${config.kit.outDir}/output/prerendered`;
|
|
222
|
-
|
|
222
|
+
|
|
223
|
+
return [
|
|
224
|
+
...copy(`${source}/pages`, dest),
|
|
225
|
+
...copy(`${source}/dependencies`, dest),
|
|
226
|
+
...copy(`${source}/data`, dest)
|
|
227
|
+
];
|
|
223
228
|
},
|
|
224
229
|
|
|
225
230
|
writeServer(dest) {
|
|
@@ -59,7 +59,7 @@ export function generate_manifest({ build_data, prerendered, relative_path, rout
|
|
|
59
59
|
assets.push(build_data.service_worker);
|
|
60
60
|
}
|
|
61
61
|
|
|
62
|
-
// In case of server
|
|
62
|
+
// In case of server-side route resolution, we need to include all matchers. Prerendered routes are not part
|
|
63
63
|
// of the server manifest, and they could reference matchers that then would not be included.
|
|
64
64
|
const matchers = new Set(
|
|
65
65
|
build_data.client?.nodes ? Object.keys(build_data.manifest_data.matchers) : undefined
|
|
@@ -100,6 +100,9 @@ export function generate_manifest({ build_data, prerendered, relative_path, rout
|
|
|
100
100
|
nodes: [
|
|
101
101
|
${(node_paths).map(loader).join(',\n')}
|
|
102
102
|
],
|
|
103
|
+
remotes: {
|
|
104
|
+
${build_data.manifest_data.remotes.map((remote) => `'${remote.hash}': ${loader(join_relative(relative_path, resolve_symlinks(build_data.server_manifest, remote.file).chunk.file))}`).join(',\n')}
|
|
105
|
+
},
|
|
103
106
|
routes: [
|
|
104
107
|
${routes.map(route => {
|
|
105
108
|
if (!route.page && !route.endpoint) return;
|
|
@@ -11,6 +11,7 @@ import { check_feature } from '../../utils/features.js';
|
|
|
11
11
|
import { createReadableStream } from '@sveltejs/kit/node';
|
|
12
12
|
import { PageNodes } from '../../utils/page_nodes.js';
|
|
13
13
|
import { build_server_nodes } from '../../exports/vite/build/build_server.js';
|
|
14
|
+
import { validate_remote_functions } from '@sveltejs/kit/internal';
|
|
14
15
|
|
|
15
16
|
export default forked(import.meta.url, analyse);
|
|
16
17
|
|
|
@@ -82,7 +83,8 @@ async function analyse({
|
|
|
82
83
|
/** @type {import('types').ServerMetadata} */
|
|
83
84
|
const metadata = {
|
|
84
85
|
nodes: [],
|
|
85
|
-
routes: new Map()
|
|
86
|
+
routes: new Map(),
|
|
87
|
+
remotes: new Map()
|
|
86
88
|
};
|
|
87
89
|
|
|
88
90
|
const nodes = await Promise.all(manifest._.nodes.map((loader) => loader()));
|
|
@@ -164,6 +166,28 @@ async function analyse({
|
|
|
164
166
|
});
|
|
165
167
|
}
|
|
166
168
|
|
|
169
|
+
// analyse remotes
|
|
170
|
+
for (const remote of manifest_data.remotes) {
|
|
171
|
+
const loader = manifest._.remotes[remote.hash];
|
|
172
|
+
const module = await loader();
|
|
173
|
+
|
|
174
|
+
validate_remote_functions(module, remote.file);
|
|
175
|
+
|
|
176
|
+
const exports = new Map();
|
|
177
|
+
|
|
178
|
+
for (const name in module) {
|
|
179
|
+
const info = /** @type {import('types').RemoteInfo} */ (module[name].__);
|
|
180
|
+
const type = info.type;
|
|
181
|
+
|
|
182
|
+
exports.set(name, {
|
|
183
|
+
type,
|
|
184
|
+
dynamic: type !== 'prerender' || info.dynamic
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
metadata.remotes.set(remote.hash, exports);
|
|
189
|
+
}
|
|
190
|
+
|
|
167
191
|
return { metadata, static_exports };
|
|
168
192
|
}
|
|
169
193
|
|
|
@@ -41,7 +41,8 @@ async function generate_fallback({ manifest_path, env }) {
|
|
|
41
41
|
},
|
|
42
42
|
prerendering: {
|
|
43
43
|
fallback: true,
|
|
44
|
-
dependencies: new Map()
|
|
44
|
+
dependencies: new Map(),
|
|
45
|
+
remote_responses: new Map()
|
|
45
46
|
},
|
|
46
47
|
read: (file) => readFileSync(join(config.files.assets, file))
|
|
47
48
|
});
|
|
@@ -14,6 +14,7 @@ import { forked } from '../../utils/fork.js';
|
|
|
14
14
|
import * as devalue from 'devalue';
|
|
15
15
|
import { createReadableStream } from '@sveltejs/kit/node';
|
|
16
16
|
import generate_fallback from './fallback.js';
|
|
17
|
+
import { stringify_remote_arg } from '../../runtime/shared.js';
|
|
17
18
|
|
|
18
19
|
export default forked(import.meta.url, prerender);
|
|
19
20
|
|
|
@@ -184,8 +185,12 @@ async function prerender({ hash, out, manifest_path, metadata, verbose, env }) {
|
|
|
184
185
|
files.add(posixify(`${config.appDir}/immutable/${file}`));
|
|
185
186
|
}
|
|
186
187
|
}
|
|
188
|
+
|
|
189
|
+
const remote_prefix = `${config.paths.base}/${config.appDir}/remote/`;
|
|
190
|
+
|
|
187
191
|
const seen = new Set();
|
|
188
192
|
const written = new Set();
|
|
193
|
+
const remote_responses = new Map();
|
|
189
194
|
|
|
190
195
|
/** @type {Map<string, Set<string>>} */
|
|
191
196
|
const expected_hashlinks = new Map();
|
|
@@ -229,7 +234,8 @@ async function prerender({ hash, out, manifest_path, metadata, verbose, env }) {
|
|
|
229
234
|
throw new Error('Cannot read clientAddress during prerendering');
|
|
230
235
|
},
|
|
231
236
|
prerendering: {
|
|
232
|
-
dependencies
|
|
237
|
+
dependencies,
|
|
238
|
+
remote_responses
|
|
233
239
|
},
|
|
234
240
|
read: (file) => {
|
|
235
241
|
// stuff we just wrote
|
|
@@ -258,7 +264,8 @@ async function prerender({ hash, out, manifest_path, metadata, verbose, env }) {
|
|
|
258
264
|
|
|
259
265
|
const body = Buffer.from(await response.arrayBuffer());
|
|
260
266
|
|
|
261
|
-
|
|
267
|
+
const category = decoded.startsWith(remote_prefix) ? 'data' : 'pages';
|
|
268
|
+
save(category, response, body, decoded, encoded, referrer, 'linked');
|
|
262
269
|
|
|
263
270
|
for (const [dependency_path, result] of dependencies) {
|
|
264
271
|
// this seems circuitous, but using new URL allows us to not care
|
|
@@ -282,8 +289,10 @@ async function prerender({ hash, out, manifest_path, metadata, verbose, env }) {
|
|
|
282
289
|
|
|
283
290
|
const body = result.body ?? new Uint8Array(await result.response.arrayBuffer());
|
|
284
291
|
|
|
292
|
+
const category = decoded_dependency_path.startsWith(remote_prefix) ? 'data' : 'dependencies';
|
|
293
|
+
|
|
285
294
|
save(
|
|
286
|
-
|
|
295
|
+
category,
|
|
287
296
|
result.response,
|
|
288
297
|
body,
|
|
289
298
|
decoded_dependency_path,
|
|
@@ -336,7 +345,7 @@ async function prerender({ hash, out, manifest_path, metadata, verbose, env }) {
|
|
|
336
345
|
}
|
|
337
346
|
|
|
338
347
|
/**
|
|
339
|
-
* @param {'pages' | 'dependencies'} category
|
|
348
|
+
* @param {'pages' | 'dependencies' | 'data'} category
|
|
340
349
|
* @param {Response} response
|
|
341
350
|
* @param {string | Uint8Array} body
|
|
342
351
|
* @param {string} decoded
|
|
@@ -451,19 +460,30 @@ async function prerender({ hash, out, manifest_path, metadata, verbose, env }) {
|
|
|
451
460
|
}
|
|
452
461
|
}
|
|
453
462
|
|
|
454
|
-
let
|
|
463
|
+
let should_prerender = false;
|
|
455
464
|
|
|
456
465
|
for (const value of prerender_map.values()) {
|
|
457
466
|
if (value) {
|
|
458
|
-
|
|
467
|
+
should_prerender = true;
|
|
459
468
|
break;
|
|
460
469
|
}
|
|
461
470
|
}
|
|
462
471
|
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
) {
|
|
472
|
+
/** @type {Array<import('types').RemoteInfo & { type: 'prerender'}>} */
|
|
473
|
+
const prerender_functions = [];
|
|
474
|
+
|
|
475
|
+
for (const loader of Object.values(manifest._.remotes)) {
|
|
476
|
+
const module = await loader();
|
|
477
|
+
|
|
478
|
+
for (const fn of Object.values(module)) {
|
|
479
|
+
if (fn?.__?.type === 'prerender') {
|
|
480
|
+
prerender_functions.push(fn.__);
|
|
481
|
+
should_prerender = true;
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
if (!should_prerender) {
|
|
467
487
|
return { prerendered, prerender_map };
|
|
468
488
|
}
|
|
469
489
|
|
|
@@ -499,6 +519,17 @@ async function prerender({ hash, out, manifest_path, metadata, verbose, env }) {
|
|
|
499
519
|
}
|
|
500
520
|
}
|
|
501
521
|
|
|
522
|
+
const transport = (await internal.get_hooks()).transport ?? {};
|
|
523
|
+
for (const info of prerender_functions) {
|
|
524
|
+
if (info.has_arg) {
|
|
525
|
+
for (const arg of (await info.inputs?.()) ?? []) {
|
|
526
|
+
void enqueue(null, remote_prefix + info.id + '/' + stringify_remote_arg(arg, transport));
|
|
527
|
+
}
|
|
528
|
+
} else {
|
|
529
|
+
void enqueue(null, remote_prefix + info.id);
|
|
530
|
+
}
|
|
531
|
+
}
|
|
532
|
+
|
|
502
533
|
await q.done();
|
|
503
534
|
|
|
504
535
|
// handle invalid fragment links
|
|
@@ -4,10 +4,11 @@ import process from 'node:process';
|
|
|
4
4
|
import colors from 'kleur';
|
|
5
5
|
import { lookup } from 'mrmime';
|
|
6
6
|
import { list_files, runtime_directory } from '../../utils.js';
|
|
7
|
-
import { posixify, resolve_entry } from '../../../utils/filesystem.js';
|
|
7
|
+
import { posixify, resolve_entry, walk } from '../../../utils/filesystem.js';
|
|
8
8
|
import { parse_route_id } from '../../../utils/routing.js';
|
|
9
9
|
import { sort_routes } from './sort.js';
|
|
10
10
|
import { isSvelte5Plus } from '../utils.js';
|
|
11
|
+
import { hash } from '../../../utils/hash.js';
|
|
11
12
|
|
|
12
13
|
/**
|
|
13
14
|
* Generates the manifest data used for the client-side manifest and types generation.
|
|
@@ -27,6 +28,7 @@ export default function create_manifest_data({
|
|
|
27
28
|
const hooks = create_hooks(config, cwd);
|
|
28
29
|
const matchers = create_matchers(config, cwd);
|
|
29
30
|
const { nodes, routes } = create_routes_and_nodes(cwd, config, fallback);
|
|
31
|
+
const remotes = create_remotes(config, cwd);
|
|
30
32
|
|
|
31
33
|
for (const route of routes) {
|
|
32
34
|
for (const param of route.params) {
|
|
@@ -41,6 +43,7 @@ export default function create_manifest_data({
|
|
|
41
43
|
hooks,
|
|
42
44
|
matchers,
|
|
43
45
|
nodes,
|
|
46
|
+
remotes,
|
|
44
47
|
routes
|
|
45
48
|
};
|
|
46
49
|
}
|
|
@@ -465,6 +468,37 @@ function create_routes_and_nodes(cwd, config, fallback) {
|
|
|
465
468
|
};
|
|
466
469
|
}
|
|
467
470
|
|
|
471
|
+
/**
|
|
472
|
+
* @param {import('types').ValidatedConfig} config
|
|
473
|
+
* @param {string} cwd
|
|
474
|
+
*/
|
|
475
|
+
function create_remotes(config, cwd) {
|
|
476
|
+
if (!config.kit.experimental.remoteFunctions) return [];
|
|
477
|
+
|
|
478
|
+
const extensions = config.kit.moduleExtensions.map((ext) => `.remote${ext}`);
|
|
479
|
+
|
|
480
|
+
/** @type {import('types').ManifestData['remotes']} */
|
|
481
|
+
const remotes = [];
|
|
482
|
+
|
|
483
|
+
// TODO could files live in other directories, including node_modules?
|
|
484
|
+
for (const dir of [config.kit.files.lib, config.kit.files.routes]) {
|
|
485
|
+
if (!fs.existsSync(dir)) continue;
|
|
486
|
+
|
|
487
|
+
for (const file of walk(dir)) {
|
|
488
|
+
if (extensions.some((ext) => file.endsWith(ext))) {
|
|
489
|
+
const posixified = posixify(path.relative(cwd, `${dir}/${file}`));
|
|
490
|
+
|
|
491
|
+
remotes.push({
|
|
492
|
+
hash: hash(posixified),
|
|
493
|
+
file: posixified
|
|
494
|
+
});
|
|
495
|
+
}
|
|
496
|
+
}
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
return remotes;
|
|
500
|
+
}
|
|
501
|
+
|
|
468
502
|
/**
|
|
469
503
|
* @param {string} project_relative
|
|
470
504
|
* @param {string} file
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import path from 'node:path';
|
|
2
2
|
import process from 'node:process';
|
|
3
|
-
import { hash } from '../../
|
|
3
|
+
import { hash } from '../../utils/hash.js';
|
|
4
4
|
import { posixify, resolve_entry } from '../../utils/filesystem.js';
|
|
5
5
|
import { s } from '../../utils/misc.js';
|
|
6
6
|
import { load_error_page, load_template } from '../config/index.js';
|
|
@@ -67,8 +67,9 @@ export async function get_hooks() {
|
|
|
67
67
|
let handle;
|
|
68
68
|
let handleFetch;
|
|
69
69
|
let handleError;
|
|
70
|
+
let handleValidationError;
|
|
70
71
|
let init;
|
|
71
|
-
${server_hooks ? `({ handle, handleFetch, handleError, init } = await import(${s(server_hooks)}));` : ''}
|
|
72
|
+
${server_hooks ? `({ handle, handleFetch, handleError, handleValidationError, init } = await import(${s(server_hooks)}));` : ''}
|
|
72
73
|
|
|
73
74
|
let reroute;
|
|
74
75
|
let transport;
|
|
@@ -78,6 +79,7 @@ export async function get_hooks() {
|
|
|
78
79
|
handle,
|
|
79
80
|
handleFetch,
|
|
80
81
|
handleError,
|
|
82
|
+
handleValidationError,
|
|
81
83
|
init,
|
|
82
84
|
reroute,
|
|
83
85
|
transport
|
package/src/exports/index.js
CHANGED
|
@@ -188,7 +188,7 @@ export function text(body, init) {
|
|
|
188
188
|
*/
|
|
189
189
|
/**
|
|
190
190
|
* Create an `ActionFailure` object. Call when form submission fails.
|
|
191
|
-
* @template
|
|
191
|
+
* @template [T=undefined]
|
|
192
192
|
* @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.
|
|
193
193
|
* @param {T} data Data associated with the failure (e.g. validation errors)
|
|
194
194
|
* @overload
|
|
@@ -49,7 +49,7 @@ export class SvelteKitError extends Error {
|
|
|
49
49
|
}
|
|
50
50
|
|
|
51
51
|
/**
|
|
52
|
-
* @template
|
|
52
|
+
* @template [T=undefined]
|
|
53
53
|
*/
|
|
54
54
|
export class ActionFailure {
|
|
55
55
|
/**
|
|
@@ -61,3 +61,5 @@ export class ActionFailure {
|
|
|
61
61
|
this.data = data;
|
|
62
62
|
}
|
|
63
63
|
}
|
|
64
|
+
|
|
65
|
+
export { validate_remote_functions } from './remote-functions.js';
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @param {Record<string, any>} module
|
|
3
|
+
* @param {string} file
|
|
4
|
+
*/
|
|
5
|
+
export function validate_remote_functions(module, file) {
|
|
6
|
+
if (module.default) {
|
|
7
|
+
throw new Error(
|
|
8
|
+
`Cannot export \`default\` from a remote module (${file}) — please use named exports instead`
|
|
9
|
+
);
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
for (const name in module) {
|
|
13
|
+
const type = module[name]?.__?.type;
|
|
14
|
+
|
|
15
|
+
if (type !== 'form' && type !== 'command' && type !== 'query' && type !== 'prerender') {
|
|
16
|
+
throw new Error(
|
|
17
|
+
`\`${name}\` exported from ${file} is invalid — all exports from this file must be remote functions`
|
|
18
|
+
);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
}
|
package/src/exports/public.d.ts
CHANGED
|
@@ -17,7 +17,8 @@ import {
|
|
|
17
17
|
RouteSegment
|
|
18
18
|
} from '../types/private.js';
|
|
19
19
|
import { BuildData, SSRNodeLoader, SSRRoute, ValidatedConfig } from 'types';
|
|
20
|
-
import type { SvelteConfig
|
|
20
|
+
import type { SvelteConfig } from '@sveltejs/vite-plugin-svelte';
|
|
21
|
+
import type { StandardSchemaV1 } from '@standard-schema/spec';
|
|
21
22
|
import {
|
|
22
23
|
RouteId as AppRouteId,
|
|
23
24
|
LayoutParams as AppLayoutParams,
|
|
@@ -78,7 +79,7 @@ type OptionalUnion<
|
|
|
78
79
|
|
|
79
80
|
declare const uniqueSymbol: unique symbol;
|
|
80
81
|
|
|
81
|
-
export interface ActionFailure<T
|
|
82
|
+
export interface ActionFailure<T = undefined> {
|
|
82
83
|
status: number;
|
|
83
84
|
data: T;
|
|
84
85
|
[uniqueSymbol]: true; // necessary or else UnpackValidationError could wrongly unpack objects with the same shape as ActionFailure
|
|
@@ -407,6 +408,16 @@ export interface KitConfig {
|
|
|
407
408
|
*/
|
|
408
409
|
privatePrefix?: string;
|
|
409
410
|
};
|
|
411
|
+
/**
|
|
412
|
+
* Experimental features which are exempt from semantic versioning. These features may be changed or removed at any time.
|
|
413
|
+
*/
|
|
414
|
+
experimental?: {
|
|
415
|
+
/**
|
|
416
|
+
* Whether to enable the experimental remote functions feature. This feature is not yet stable and may be changed or removed at any time.
|
|
417
|
+
* @default false
|
|
418
|
+
*/
|
|
419
|
+
remoteFunctions?: boolean;
|
|
420
|
+
};
|
|
410
421
|
/**
|
|
411
422
|
* Where to find various files within your project.
|
|
412
423
|
*/
|
|
@@ -774,6 +785,14 @@ export type HandleServerError = (input: {
|
|
|
774
785
|
message: string;
|
|
775
786
|
}) => MaybePromise<void | App.Error>;
|
|
776
787
|
|
|
788
|
+
/**
|
|
789
|
+
* The [`handleValidationError`](https://svelte.dev/docs/kit/hooks#Server-hooks-handleValidationError) hook runs when the argument to a remote function fails validation.
|
|
790
|
+
*
|
|
791
|
+
* It will be called with the validation issues and the event, and must return an object shape that matches `App.Error`.
|
|
792
|
+
*/
|
|
793
|
+
export type HandleValidationError<Issue extends StandardSchemaV1.Issue = StandardSchemaV1.Issue> =
|
|
794
|
+
(input: { issues: Issue[]; event: RequestEvent }) => MaybePromise<App.Error>;
|
|
795
|
+
|
|
777
796
|
/**
|
|
778
797
|
* The client-side [`handleError`](https://svelte.dev/docs/kit/hooks#Shared-hooks-handleError) hook runs when an unexpected error is thrown while navigating.
|
|
779
798
|
*
|
|
@@ -1248,6 +1267,11 @@ export interface RequestEvent<
|
|
|
1248
1267
|
* `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.
|
|
1249
1268
|
*/
|
|
1250
1269
|
isSubRequest: boolean;
|
|
1270
|
+
/**
|
|
1271
|
+
* `true` if the request comes from the client via a remote function. The `url` property will be stripped of the internal information
|
|
1272
|
+
* related to the data request in this case. Use this property instead if the distinction is important to you.
|
|
1273
|
+
*/
|
|
1274
|
+
isRemoteRequest: boolean;
|
|
1251
1275
|
}
|
|
1252
1276
|
|
|
1253
1277
|
/**
|
|
@@ -1322,6 +1346,8 @@ export interface SSRManifest {
|
|
|
1322
1346
|
_: {
|
|
1323
1347
|
client: NonNullable<BuildData['client']>;
|
|
1324
1348
|
nodes: SSRNodeLoader[];
|
|
1349
|
+
/** hashed filename -> import to that file */
|
|
1350
|
+
remotes: Record<string, () => Promise<any>>;
|
|
1325
1351
|
routes: SSRRoute[];
|
|
1326
1352
|
prerendered_routes: Set<string>;
|
|
1327
1353
|
matchers: () => Promise<Record<string, ParamMatcher>>;
|
|
@@ -1499,4 +1525,138 @@ export interface Snapshot<T = any> {
|
|
|
1499
1525
|
restore: (snapshot: T) => void;
|
|
1500
1526
|
}
|
|
1501
1527
|
|
|
1528
|
+
/**
|
|
1529
|
+
* The return value of a remote `form` function. See [Remote functions](https://svelte.dev/docs/kit/remote-functions#form) for full documentation.
|
|
1530
|
+
*/
|
|
1531
|
+
export type RemoteForm<Result> = {
|
|
1532
|
+
method: 'POST';
|
|
1533
|
+
/** The URL to send the form to. */
|
|
1534
|
+
action: string;
|
|
1535
|
+
/** Event handler that intercepts the form submission on the client to prevent a full page reload */
|
|
1536
|
+
onsubmit: (event: SubmitEvent) => void;
|
|
1537
|
+
/** Use the `enhance` method to influence what happens when the form is submitted. */
|
|
1538
|
+
enhance(
|
|
1539
|
+
callback: (opts: {
|
|
1540
|
+
form: HTMLFormElement;
|
|
1541
|
+
data: FormData;
|
|
1542
|
+
submit: () => Promise<void> & {
|
|
1543
|
+
updates: (...queries: Array<RemoteQuery<any> | RemoteQueryOverride>) => Promise<void>;
|
|
1544
|
+
};
|
|
1545
|
+
}) => void
|
|
1546
|
+
): {
|
|
1547
|
+
method: 'POST';
|
|
1548
|
+
action: string;
|
|
1549
|
+
onsubmit: (event: SubmitEvent) => void;
|
|
1550
|
+
};
|
|
1551
|
+
/**
|
|
1552
|
+
* Create an instance of the form for the given key.
|
|
1553
|
+
* The key is stringified and used for deduplication to potentially reuse existing instances.
|
|
1554
|
+
* Useful when you have multiple forms that use the same remote form action, for example in a loop.
|
|
1555
|
+
* ```svelte
|
|
1556
|
+
* {#each todos as todo}
|
|
1557
|
+
* {@const todoForm = updateTodo.for(todo.id)}
|
|
1558
|
+
* <form {...todoForm}>
|
|
1559
|
+
* {#if todoForm.result?.invalid}<p>Invalid data</p>{/if}
|
|
1560
|
+
* ...
|
|
1561
|
+
* </form>
|
|
1562
|
+
* {/each}
|
|
1563
|
+
* ```
|
|
1564
|
+
*/
|
|
1565
|
+
for(key: string | number | boolean): Omit<RemoteForm<Result>, 'for'>;
|
|
1566
|
+
/** The result of the form submission */
|
|
1567
|
+
get result(): Result | undefined;
|
|
1568
|
+
/** Spread this onto a `<button>` or `<input type="submit">` */
|
|
1569
|
+
buttonProps: {
|
|
1570
|
+
type: 'submit';
|
|
1571
|
+
formmethod: 'POST';
|
|
1572
|
+
formaction: string;
|
|
1573
|
+
onclick: (event: Event) => void;
|
|
1574
|
+
/** Use the `enhance` method to influence what happens when the form is submitted. */
|
|
1575
|
+
enhance(
|
|
1576
|
+
callback: (opts: {
|
|
1577
|
+
form: HTMLFormElement;
|
|
1578
|
+
data: FormData;
|
|
1579
|
+
submit: () => Promise<void> & {
|
|
1580
|
+
updates: (...queries: Array<RemoteQuery<any> | RemoteQueryOverride>) => Promise<void>;
|
|
1581
|
+
};
|
|
1582
|
+
}) => void
|
|
1583
|
+
): {
|
|
1584
|
+
type: 'submit';
|
|
1585
|
+
formmethod: 'POST';
|
|
1586
|
+
formaction: string;
|
|
1587
|
+
onclick: (event: Event) => void;
|
|
1588
|
+
};
|
|
1589
|
+
};
|
|
1590
|
+
};
|
|
1591
|
+
|
|
1592
|
+
/**
|
|
1593
|
+
* The return value of a remote `command` function. See [Remote functions](https://svelte.dev/docs/kit/remote-functions#command) for full documentation.
|
|
1594
|
+
*/
|
|
1595
|
+
export type RemoteCommand<Input, Output> = (arg: Input) => Promise<Awaited<Output>> & {
|
|
1596
|
+
updates(...queries: Array<RemoteQuery<any> | RemoteQueryOverride>): Promise<Awaited<Output>>;
|
|
1597
|
+
};
|
|
1598
|
+
|
|
1599
|
+
export type RemoteResource<T> = Promise<Awaited<T>> & {
|
|
1600
|
+
/** The error in case the query fails. Most often this is a [`HttpError`](https://svelte.dev/docs/kit/@sveltejs-kit#HttpError) but it isn't guaranteed to be. */
|
|
1601
|
+
get error(): any;
|
|
1602
|
+
/** `true` before the first result is available and during refreshes */
|
|
1603
|
+
get loading(): boolean;
|
|
1604
|
+
} & (
|
|
1605
|
+
| {
|
|
1606
|
+
/** The current value of the query. Undefined until `ready` is `true` */
|
|
1607
|
+
get current(): undefined;
|
|
1608
|
+
ready: false;
|
|
1609
|
+
}
|
|
1610
|
+
| {
|
|
1611
|
+
/** The current value of the query. Undefined until `ready` is `true` */
|
|
1612
|
+
get current(): Awaited<T>;
|
|
1613
|
+
ready: true;
|
|
1614
|
+
}
|
|
1615
|
+
);
|
|
1616
|
+
|
|
1617
|
+
export type RemoteQuery<T> = RemoteResource<T> & {
|
|
1618
|
+
/**
|
|
1619
|
+
* On the client, this function will re-fetch the query from the server.
|
|
1620
|
+
*
|
|
1621
|
+
* On the server, this can be called in the context of a `command` or `form` and the refreshed data will accompany the action response back to the client.
|
|
1622
|
+
* This prevents SvelteKit needing to refresh all queries on the page in a second server round-trip.
|
|
1623
|
+
*/
|
|
1624
|
+
refresh(): Promise<void>;
|
|
1625
|
+
/**
|
|
1626
|
+
* Temporarily override the value of a query. This is used with the `updates` method of a [command](https://svelte.dev/docs/kit/remote-functions#command-Single-flight-mutations) or [enhanced form submission](https://svelte.dev/docs/kit/remote-functions#form-enhance) to provide optimistic updates.
|
|
1627
|
+
*
|
|
1628
|
+
* ```svelte
|
|
1629
|
+
* <script>
|
|
1630
|
+
* import { getTodos, addTodo } from './todos.remote.js';
|
|
1631
|
+
* const todos = getTodos();
|
|
1632
|
+
* </script>
|
|
1633
|
+
*
|
|
1634
|
+
* <form {...addTodo.enhance(async ({ data, submit }) => {
|
|
1635
|
+
* await submit().updates(
|
|
1636
|
+
* todos.withOverride((todos) => [...todos, { text: data.get('text') }])
|
|
1637
|
+
* );
|
|
1638
|
+
* }}>
|
|
1639
|
+
* <input type="text" name="text" />
|
|
1640
|
+
* <button type="submit">Add Todo</button>
|
|
1641
|
+
* </form>
|
|
1642
|
+
* ```
|
|
1643
|
+
*/
|
|
1644
|
+
withOverride(update: (current: Awaited<T>) => Awaited<T>): RemoteQueryOverride;
|
|
1645
|
+
};
|
|
1646
|
+
|
|
1647
|
+
export interface RemoteQueryOverride {
|
|
1648
|
+
_key: string;
|
|
1649
|
+
release(): void;
|
|
1650
|
+
}
|
|
1651
|
+
|
|
1652
|
+
/**
|
|
1653
|
+
* The return value of a remote `prerender` function. See [Remote functions](https://svelte.dev/docs/kit/remote-functions#prerender) for full documentation.
|
|
1654
|
+
*/
|
|
1655
|
+
export type RemotePrerenderFunction<Input, Output> = (arg: Input) => RemoteResource<Output>;
|
|
1656
|
+
|
|
1657
|
+
/**
|
|
1658
|
+
* The return value of a remote `query` function. See [Remote functions](https://svelte.dev/docs/kit/remote-functions#query) for full documentation.
|
|
1659
|
+
*/
|
|
1660
|
+
export type RemoteQueryFunction<Input, Output> = (arg: Input) => RemoteQuery<Output>;
|
|
1661
|
+
|
|
1502
1662
|
export * from './index.js';
|